gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (8791d4ea6 -> eebb85bef)


From: gnunet
Subject: [taler-wallet-core] branch master updated (8791d4ea6 -> eebb85bef)
Date: Fri, 27 Jan 2023 19:09:24 +0100

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

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

    from 8791d4ea6 -remove debug logging
     new 7a3717125 no more storybook
     new 1b2b5d62d add use-template button
     new eebb85bef webhook api

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../merchant-backoffice-ui/.storybook/.babelrc     |  25 ----
 packages/merchant-backoffice-ui/.storybook/main.js |  57 -------
 .../merchant-backoffice-ui/.storybook/preview.js   |  74 ---------
 .../merchant-backoffice-ui/src/InstanceRoutes.tsx  |  64 ++++++++
 .../src/components/form/Input.tsx                  |   1 +
 .../src/components/form/InputWithAddon.tsx         |   1 +
 .../src/components/menu/SideBar.tsx                |  10 ++
 .../merchant-backoffice-ui/src/declaration.d.ts    |  81 +++++++++-
 .../merchant-backoffice-ui/src/hooks/backend.ts    |  23 +++
 .../merchant-backoffice-ui/src/hooks/templates.ts  |  15 +-
 .../merchant-backoffice-ui/src/hooks/webhooks.ts   | 165 +++++++++++++++++++++
 .../src/paths/instance/details/DetailPage.tsx      |   4 +-
 .../src/paths/instance/details/stories.tsx         |   4 +-
 .../instance/orders/create/Create.stories.tsx      |   2 +-
 .../paths/instance/orders/create/CreatePage.tsx    |   4 +-
 .../paths/instance/templates/create/CreatePage.tsx |   2 +-
 .../src/paths/instance/templates/list/ListPage.tsx |   3 +
 .../src/paths/instance/templates/list/Table.tsx    |  30 +++-
 .../src/paths/instance/templates/list/index.tsx    |   5 +
 .../paths/instance/templates/update/UpdatePage.tsx |   2 +-
 .../Create.stories.tsx => use/Use.stories.tsx}     |   2 +-
 .../CreatePage.tsx => templates/use/UsePage.tsx}   |  82 ++++------
 .../instance/templates/{update => use}/index.tsx   |  41 ++---
 .../src/paths/instance/update/Update.stories.tsx   |   4 +-
 .../create/Create.stories.tsx                      |   2 +-
 .../{transfers => webhooks}/create/CreatePage.tsx  |  88 +++++------
 .../{templates => webhooks}/create/index.tsx       |  12 +-
 .../{templates => webhooks}/list/List.stories.tsx  |   0
 .../{templates => webhooks}/list/ListPage.tsx      |  12 +-
 .../{templates => webhooks}/list/Table.tsx         |  62 +++++---
 .../{templates => webhooks}/list/index.tsx         |  26 ++--
 .../update/Update.stories.tsx                      |   0
 .../{templates => webhooks}/update/UpdatePage.tsx  |  92 +++++-------
 .../{templates => webhooks}/update/index.tsx       |  20 +--
 34 files changed, 593 insertions(+), 422 deletions(-)
 delete mode 100644 packages/merchant-backoffice-ui/.storybook/.babelrc
 delete mode 100644 packages/merchant-backoffice-ui/.storybook/main.js
 delete mode 100644 packages/merchant-backoffice-ui/.storybook/preview.js
 create mode 100644 packages/merchant-backoffice-ui/src/hooks/webhooks.ts
 copy 
packages/merchant-backoffice-ui/src/paths/instance/templates/{create/Create.stories.tsx
 => use/Use.stories.tsx} (93%)
 copy 
packages/merchant-backoffice-ui/src/paths/instance/{transfers/create/CreatePage.tsx
 => templates/use/UsePage.tsx} (55%)
 copy packages/merchant-backoffice-ui/src/paths/instance/templates/{update => 
use}/index.tsx (76%)
 copy packages/merchant-backoffice-ui/src/paths/instance/{templates => 
webhooks}/create/Create.stories.tsx (96%)
 copy packages/merchant-backoffice-ui/src/paths/instance/{transfers => 
webhooks}/create/CreatePage.tsx (56%)
 copy packages/merchant-backoffice-ui/src/paths/instance/{templates => 
webhooks}/create/index.tsx (82%)
 copy packages/merchant-backoffice-ui/src/paths/instance/{templates => 
webhooks}/list/List.stories.tsx (100%)
 copy packages/merchant-backoffice-ui/src/paths/instance/{templates => 
webhooks}/list/ListPage.tsx (85%)
 copy packages/merchant-backoffice-ui/src/paths/instance/{templates => 
webhooks}/list/Table.tsx (75%)
 copy packages/merchant-backoffice-ui/src/paths/instance/{templates => 
webhooks}/list/index.tsx (82%)
 copy packages/merchant-backoffice-ui/src/paths/instance/{templates => 
webhooks}/update/Update.stories.tsx (100%)
 copy packages/merchant-backoffice-ui/src/paths/instance/{templates => 
webhooks}/update/UpdatePage.tsx (54%)
 copy packages/merchant-backoffice-ui/src/paths/instance/{templates => 
webhooks}/update/index.tsx (86%)

diff --git a/packages/merchant-backoffice-ui/.storybook/.babelrc 
b/packages/merchant-backoffice-ui/.storybook/.babelrc
deleted file mode 100644
index 1b301f996..000000000
--- a/packages/merchant-backoffice-ui/.storybook/.babelrc
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 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/>
- */
-
- /**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-{
-    "presets": [
-        "preact-cli/babel"
-    ]
-}
\ No newline at end of file
diff --git a/packages/merchant-backoffice-ui/.storybook/main.js 
b/packages/merchant-backoffice-ui/.storybook/main.js
deleted file mode 100644
index e24e22adc..000000000
--- a/packages/merchant-backoffice-ui/.storybook/main.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 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/>
- */
-
-/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-
-module.exports = {
-  "stories": [
-    "../src/**/*.stories.mdx",
-    "../src/**/*.stories.@(js|jsx|ts|tsx)"
-  ],
-  "addons": [
-    "@storybook/preset-scss",
-    "@storybook/addon-a11y",
-    "@storybook/addon-essentials" //docs, control, actions, viewpot, toolbar, 
background
-  ],
-  // sb does not yet support new jsx transform by default
-  // https://github.com/storybookjs/storybook/issues/12881
-  // https://github.com/storybookjs/storybook/issues/12952
-  babel: async (options) => ({
-    ...options,
-    presets: [
-      ...options.presets,
-      [
-        '@babel/preset-react', {
-          runtime: 'automatic',
-        },
-        'preset-react-jsx-transform' 
-      ],
-    ],
-  }),
-  webpackFinal: (config) => {
-    // should be removed after storybook 6.3
-    // 
https://github.com/storybookjs/storybook/issues/12853#issuecomment-821576113
-    config.resolve.alias = {
-      react: "preact/compat",
-      "react-dom": "preact/compat",
-    };
-    return config;
-  },
-}
\ No newline at end of file
diff --git a/packages/merchant-backoffice-ui/.storybook/preview.js 
b/packages/merchant-backoffice-ui/.storybook/preview.js
deleted file mode 100644
index 7ddd061dc..000000000
--- a/packages/merchant-backoffice-ui/.storybook/preview.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2023 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 "../src/scss/main.scss"
-import { ConfigContextProvider } from '../src/context/config'
-import { InstanceContextProvider } from '../src/context/instance'
-import { TranslationProvider } from '../src/context/translation'
-import { BackendContextProvider } from '../src/context/backend'
-import { h } from 'preact';
-
-const mockConfig = {
-  backendURL: 'http://demo.taler.net',
-  currency: 'TESTKUDOS'
-}
-
-const mockInstance = {
-  id: 'instance-id',
-  token: 'instance-token',
-  admin: false,
-}
-
-const mockBackend = {
-  url: 'http://merchant.url',
-  token: 'default-token',
-  triedToLog: false,
-}
-
-export const parameters = {
-  controls: { expanded: true },
-  // actions: { argTypesRegex: "^on.*" },
-}
-
-export const globalTypes = {
-  locale: {
-    name: 'Locale',
-    description: 'Internationalization locale',
-    defaultValue: 'en',
-    toolbar: {
-      icon: 'globe',
-      items: [
-        { value: 'en', right: 'πŸ‡ΊπŸ‡Έ', title: 'English' },
-        { value: 'es', right: 'πŸ‡ͺπŸ‡Έ', title: 'Spanish' },
-      ],
-    },
-  },
-};
-
-export const decorators = [
-  (Story, { globals }) => <TranslationProvider initial='en' 
forceLang={globals.locale}>
-    <Story />
-  </TranslationProvider>,
-  (Story) => <ConfigContextProvider value={mockConfig}>
-    <Story />
-  </ConfigContextProvider>,
-  (Story) => <InstanceContextProvider value={mockInstance}>
-    <Story />
-  </InstanceContextProvider>,
-  (Story) => <BackendContextProvider defaultUrl={mockBackend.url}>
-    <Story />
-  </BackendContextProvider>,
-];
diff --git a/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx 
b/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx
index 1c55572bb..56f223620 100644
--- a/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx
+++ b/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx
@@ -48,8 +48,12 @@ import ReservesCreatePage from 
"./paths/instance/reserves/create/index.js";
 import ReservesDetailsPage from "./paths/instance/reserves/details/index.js";
 import ReservesListPage from "./paths/instance/reserves/list/index.js";
 import TemplateCreatePage from "./paths/instance/templates/create/index.js";
+import TemplateUsePage from "./paths/instance/templates/use/index.js";
 import TemplateListPage from "./paths/instance/templates/list/index.js";
 import TemplateUpdatePage from "./paths/instance/templates/update/index.js";
+import WebhookCreatePage from "./paths/instance/webhooks/create/index.js";
+import WebhookListPage from "./paths/instance/webhooks/list/index.js";
+import WebhookUpdatePage from "./paths/instance/webhooks/update/index.js";
 import TransferCreatePage from "./paths/instance/transfers/create/index.js";
 import TransferListPage from "./paths/instance/transfers/list/index.js";
 import InstanceUpdatePage, {
@@ -85,6 +89,11 @@ export enum InstancePaths {
   templates_list = "/templates",
   templates_update = "/templates/:tid/update",
   templates_new = "/templates/new",
+  templates_use = "/templates/:tid/use",
+
+  webhooks_list = "/webhooks",
+  webhooks_update = "/webhooks/:tid/update",
+  webhooks_new = "/webhooks/new",
 }
 
 // eslint-disable-next-line @typescript-eslint/no-empty-function
@@ -387,6 +396,45 @@ export function InstanceRoutes({
             route(InstancePaths.transfers_list);
           }}
         />
+        {/**
+         * Webhooks pages
+         */}
+        <Route
+          path={InstancePaths.webhooks_list}
+          component={WebhookListPage}
+          onUnauthorized={LoginPageAccessDenied}
+          onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
+          onLoadError={ServerErrorRedirectTo(InstancePaths.update)}
+          onCreate={() => {
+            route(InstancePaths.webhooks_new);
+          }}
+          onSelect={(id: string) => {
+            route(InstancePaths.webhooks_update.replace(":tid", id));
+          }}
+        />
+        <Route
+          path={InstancePaths.webhooks_update}
+          component={WebhookUpdatePage}
+          onConfirm={() => {
+            route(InstancePaths.webhooks_list);
+          }}
+          onUnauthorized={LoginPageAccessDenied}
+          onLoadError={ServerErrorRedirectTo(InstancePaths.webhooks_list)}
+          onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
+          onBack={() => {
+            route(InstancePaths.webhooks_list);
+          }}
+        />
+        <Route
+          path={InstancePaths.webhooks_new}
+          component={WebhookCreatePage}
+          onConfirm={() => {
+            route(InstancePaths.webhooks_list);
+          }}
+          onBack={() => {
+            route(InstancePaths.webhooks_list);
+          }}
+        />
         {/**
          * Templates pages
          */}
@@ -399,6 +447,9 @@ export function InstanceRoutes({
           onCreate={() => {
             route(InstancePaths.templates_new);
           }}
+          onNewOrder={(id: string) => {
+            route(InstancePaths.templates_use.replace(":tid", id));
+          }}
           onSelect={(id: string) => {
             route(InstancePaths.templates_update.replace(":tid", id));
           }}
@@ -426,6 +477,19 @@ export function InstanceRoutes({
             route(InstancePaths.templates_list);
           }}
         />
+        <Route
+          path={InstancePaths.templates_use}
+          component={TemplateUsePage}
+          onOrderCreated={(id: string) => {
+            route(InstancePaths.order_details.replace(":oid", id));
+          }}
+          onUnauthorized={LoginPageAccessDenied}
+          onLoadError={ServerErrorRedirectTo(InstancePaths.templates_list)}
+          onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
+          onBack={() => {
+            route(InstancePaths.templates_list);
+          }}
+        />
 
         {/**
          * reserves pages
diff --git a/packages/merchant-backoffice-ui/src/components/form/Input.tsx 
b/packages/merchant-backoffice-ui/src/components/form/Input.tsx
index 54140ba4d..c1ddcb064 100644
--- a/packages/merchant-backoffice-ui/src/components/form/Input.tsx
+++ b/packages/merchant-backoffice-ui/src/components/form/Input.tsx
@@ -92,6 +92,7 @@ export function Input<T>({
               inputType={inputType}
               placeholder={placeholder}
               readonly={readonly}
+              disabled={readonly}
               name={String(name)}
               value={toStr(value)}
               onChange={(e: h.JSX.TargetedEvent<HTMLInputElement>): void =>
diff --git 
a/packages/merchant-backoffice-ui/src/components/form/InputWithAddon.tsx 
b/packages/merchant-backoffice-ui/src/components/form/InputWithAddon.tsx
index 620922584..e5118c722 100644
--- a/packages/merchant-backoffice-ui/src/components/form/InputWithAddon.tsx
+++ b/packages/merchant-backoffice-ui/src/components/form/InputWithAddon.tsx
@@ -86,6 +86,7 @@ export function InputWithAddon<T>({
                 type={inputType}
                 placeholder={placeholder}
                 readonly={readonly}
+                disabled={readonly}
                 name={String(name)}
                 value={toStr(value)}
                 onChange={(e): void => 
onChange(fromStr(e.currentTarget.value))}
diff --git a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx 
b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
index 92d144b1a..c7ece9ca2 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
@@ -140,6 +140,16 @@ export function Sidebar({
                   <span class="menu-item-label">Reserves</span>
                 </a>
               </li>
+              <li>
+                <a href={"/webhooks"} class="has-icon">
+                  <span class="icon">
+                    <i class="mdi mdi-newspaper" />
+                  </span>
+                  <span class="menu-item-label">
+                    <i18n.Translate>Webhooks</i18n.Translate>
+                  </span>
+                </a>
+              </li>
               {needKYC && (
                 <li>
                   <a href={"/kyc"} class="has-icon">
diff --git a/packages/merchant-backoffice-ui/src/declaration.d.ts 
b/packages/merchant-backoffice-ui/src/declaration.d.ts
index 25b66bdea..32e6b44ea 100644
--- a/packages/merchant-backoffice-ui/src/declaration.d.ts
+++ b/packages/merchant-backoffice-ui/src/declaration.d.ts
@@ -1347,7 +1347,7 @@ export namespace MerchantBackend {
 
     interface UsingTemplateDetails {
       // Subject of the template
-      subject?: string;
+      summary?: string;
 
       // The amount entered by the customer.
       amount?: Amount;
@@ -1355,10 +1355,87 @@ export namespace MerchantBackend {
 
     interface UsingTemplateResponse {
       // After enter the request. The user will be pay with a taler URL.
-      taler_url: string;
+      order_id: string,
+      token: string,
     }
   }
 
+  namespace Webhooks {
+    interface WebhookAddDetails {
+
+      // Webhook ID to use.
+      webhook_id: string;
+
+      // The event of the webhook: why the webhook is used.
+      event_type: string;
+
+      // URL of the webhook where the customer will be redirected.
+      url: string;
+
+      // Method used by the webhook
+      http_method: string;
+
+      // Header template of the webhook
+      header_template?: string;
+
+      // Body template by the webhook
+      body_template?: string;
+
+    }
+    interface WebhookPatchDetails {
+
+      // The event of the webhook: why the webhook is used.
+      event_type: string;
+
+      // URL of the webhook where the customer will be redirected.
+      url: string;
+
+      // Method used by the webhook
+      http_method: string;
+
+      // Header template of the webhook
+      header_template?: string;
+
+      // Body template by the webhook
+      body_template?: string;
+
+    }
+    interface WebhookSummaryResponse {
+
+      // List of webhooks that are present in our backend.
+      webhooks: WebhookEntry[];
+
+    }
+    interface WebhookEntry {
+
+      // Webhook identifier, as found in the webhook.
+      webhook_id: string;
+
+      // The event of the webhook: why the webhook is used.
+      event_type: string;
+
+    }
+    interface WebhookDetails {
+
+      // The event of the webhook: why the webhook is used.
+      event_type: string;
+
+      // URL of the webhook where the customer will be redirected.
+      url: string;
+
+      // Method used by the webhook
+      http_method: string;
+
+      // Header template of the webhook
+      header_template?: string;
+
+      // Body template by the webhook
+      body_template?: string;
+
+    }
+
+  }
+
   interface ContractTerms {
     // Human-readable description of the whole purchase
     summary: string;
diff --git a/packages/merchant-backoffice-ui/src/hooks/backend.ts 
b/packages/merchant-backoffice-ui/src/hooks/backend.ts
index a0639a4a0..3f3db2fa1 100644
--- a/packages/merchant-backoffice-ui/src/hooks/backend.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/backend.ts
@@ -115,6 +115,11 @@ interface useBackendInstanceRequestType {
     position?: string,
     delta?: number,
   ) => Promise<HttpResponseOk<T>>;
+  webhookFetcher: <T>(
+    path: string,
+    position?: string,
+    delta?: number,
+  ) => Promise<HttpResponseOk<T>>;
 }
 interface useBackendBaseRequestType {
   request: <T>(
@@ -274,6 +279,23 @@ export function useBackendInstanceRequest(): 
useBackendInstanceRequestType {
     [backend, token],
   );
 
+  const webhookFetcher = useCallback(
+    function webhookFetcherImpl<T>(
+      path: string,
+      position?: string,
+      delta?: number,
+    ): Promise<HttpResponseOk<T>> {
+      const params: any = {};
+      if (delta !== undefined) {
+        params.limit = delta;
+      }
+      if (position !== undefined) params.offset = position;
+
+      return requestHandler<T>(backend, path, { params, token });
+    },
+    [backend, token],
+  );
+
   return {
     request,
     fetcher,
@@ -283,5 +305,6 @@ export function useBackendInstanceRequest(): 
useBackendInstanceRequestType {
     tipsDetailFetcher,
     transferFetcher,
     templateFetcher,
+    webhookFetcher,
   };
 }
diff --git a/packages/merchant-backoffice-ui/src/hooks/templates.ts 
b/packages/merchant-backoffice-ui/src/hooks/templates.ts
index 672eaf792..3a28b903d 100644
--- a/packages/merchant-backoffice-ui/src/hooks/templates.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/templates.ts
@@ -62,14 +62,14 @@ export function useTemplateAPI(): TemplateAPI {
     return res;
   };
 
-  const createOrder = async (
+  const createOrderFromTemplate = async (
     templateId: string,
     data: MerchantBackend.Template.UsingTemplateDetails,
   ): Promise<
     HttpResponseOk<MerchantBackend.Template.UsingTemplateResponse>
   > => {
     const res = await request<MerchantBackend.Template.UsingTemplateResponse>(
-      `/private/templates/${templateId}`,
+      `/templates/${templateId}`,
       {
         method: "POST",
         data,
@@ -79,7 +79,7 @@ export function useTemplateAPI(): TemplateAPI {
     return res;
   };
 
-  return { createTemplate, updateTemplate, deleteTemplate, createOrder };
+  return { createTemplate, updateTemplate, deleteTemplate, 
createOrderFromTemplate };
 }
 
 export interface TemplateAPI {
@@ -91,7 +91,7 @@ export interface TemplateAPI {
     data: MerchantBackend.Template.TemplatePatchDetails,
   ) => Promise<HttpResponseOk<void>>;
   deleteTemplate: (id: string) => Promise<HttpResponseOk<void>>;
-  createOrder: (
+  createOrderFromTemplate: (
     id: string,
     data: MerchantBackend.Template.UsingTemplateDetails,
   ) => Promise<HttpResponseOk<MerchantBackend.Template.UsingTemplateResponse>>;
@@ -174,10 +174,9 @@ export function useInstanceTemplates(
       if (afterData.data.templates.length < MAX_RESULT_SIZE) {
         setPageAfter(pageAfter + 1);
       } else {
-        const from = `${
-          afterData.data.templates[afterData.data.templates.length - 1]
-            .template_id
-        }`;
+        const from = 
`${afterData.data.templates[afterData.data.templates.length - 1]
+          .template_id
+          }`;
         if (from && updatePosition) updatePosition(from);
       }
     },
diff --git a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts 
b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts
new file mode 100644
index 000000000..9f196cefa
--- /dev/null
+++ b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts
@@ -0,0 +1,165 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021-2023 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 { MerchantBackend } from "../declaration.js";
+import { useMatchMutate, useBackendInstanceRequest } from "./backend.js";
+import useSWR from "swr";
+import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils/constants.js";
+import { useEffect, useState } from "preact/hooks";
+import {
+  HttpError,
+  HttpResponse,
+  HttpResponseOk,
+  HttpResponsePaginated,
+} from "../utils/request.js";
+
+export function useWebhookAPI(): WebhookAPI {
+  const mutateAll = useMatchMutate();
+  const { request } = useBackendInstanceRequest();
+
+  const createWebhook = async (
+    data: MerchantBackend.Webhooks.WebhookAddDetails,
+  ): Promise<HttpResponseOk<void>> => {
+    const res = await request<void>(`/private/webhooks`, {
+      method: "POST",
+      data,
+    });
+    await mutateAll(/.*private\/webhooks.*/);
+    return res;
+  };
+
+  const updateWebhook = async (
+    webhookId: string,
+    data: MerchantBackend.Webhooks.WebhookPatchDetails,
+  ): Promise<HttpResponseOk<void>> => {
+    const res = await request<void>(`/private/webhooks/${webhookId}`, {
+      method: "PATCH",
+      data,
+    });
+    await mutateAll(/.*private\/webhooks.*/);
+    return res;
+  };
+
+  const deleteWebhook = async (
+    webhookId: string,
+  ): Promise<HttpResponseOk<void>> => {
+    const res = await request<void>(`/private/webhooks/${webhookId}`, {
+      method: "DELETE",
+    });
+    await mutateAll(/.*private\/webhooks.*/);
+    return res;
+  };
+
+  return { createWebhook, updateWebhook, deleteWebhook };
+}
+
+export interface WebhookAPI {
+  createWebhook: (
+    data: MerchantBackend.Webhooks.WebhookAddDetails,
+  ) => Promise<HttpResponseOk<void>>;
+  updateWebhook: (
+    id: string,
+    data: MerchantBackend.Webhooks.WebhookPatchDetails,
+  ) => Promise<HttpResponseOk<void>>;
+  deleteWebhook: (id: string) => Promise<HttpResponseOk<void>>;
+}
+
+export interface InstanceWebhookFilter {
+  //FIXME: add filter to the webhook list
+  position?: string;
+}
+
+export function useInstanceWebhooks(
+  args?: InstanceWebhookFilter,
+  updatePosition?: (id: string) => void,
+): HttpResponsePaginated<MerchantBackend.Webhooks.WebhookSummaryResponse> {
+  const { webhookFetcher } = useBackendInstanceRequest();
+
+  const [pageAfter, setPageAfter] = useState(1);
+
+  const totalAfter = pageAfter * PAGE_SIZE;
+
+  const {
+    data: afterData,
+    error: afterError,
+    isValidating: loadingAfter,
+  } = useSWR<
+    HttpResponseOk<MerchantBackend.Webhooks.WebhookSummaryResponse>,
+    HttpError
+  >([`/private/webhooks`, args?.position, -totalAfter], webhookFetcher);
+
+  const [lastAfter, setLastAfter] = useState<
+    HttpResponse<MerchantBackend.Webhooks.WebhookSummaryResponse>
+  >({ loading: true });
+  useEffect(() => {
+    if (afterData) setLastAfter(afterData);
+  }, [afterData]);
+
+  if (afterError) return afterError;
+
+  const isReachingEnd =
+    afterData && afterData.data.webhooks.length < totalAfter;
+  const isReachingStart = false;
+
+  const pagination = {
+    isReachingEnd,
+    isReachingStart,
+    loadMore: () => {
+      if (!afterData || isReachingEnd) return;
+      if (afterData.data.webhooks.length < MAX_RESULT_SIZE) {
+        setPageAfter(pageAfter + 1);
+      } else {
+        const from = `${afterData.data.webhooks[afterData.data.webhooks.length 
- 1]
+          .webhook_id
+          }`;
+        if (from && updatePosition) updatePosition(from);
+      }
+    },
+    loadMorePrev: () => {
+      return
+    },
+  };
+
+  const webhooks = !afterData ? [] : (afterData || lastAfter).data.webhooks;
+
+  if (loadingAfter)
+    return { loading: true, data: { webhooks } };
+  if (afterData) {
+    return { ok: true, data: { webhooks }, ...pagination };
+  }
+  return { loading: true };
+}
+
+export function useWebhookDetails(
+  webhookId: string,
+): HttpResponse<MerchantBackend.Webhooks.WebhookDetails> {
+  const { webhookFetcher } = useBackendInstanceRequest();
+
+  const { data, error, isValidating } = useSWR<
+    HttpResponseOk<MerchantBackend.Webhooks.WebhookDetails>,
+    HttpError
+  >([`/private/webhooks/${webhookId}`], webhookFetcher, {
+    refreshInterval: 0,
+    refreshWhenHidden: false,
+    revalidateOnFocus: false,
+    revalidateOnReconnect: false,
+    refreshWhenOffline: false,
+  });
+
+  if (isValidating) return { loading: true, data: data?.data };
+  if (data) return data;
+  if (error) return error;
+  return { loading: true };
+}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/details/DetailPage.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/details/DetailPage.tsx
index 4ab415e85..9a35b0797 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/details/DetailPage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/details/DetailPage.tsx
@@ -40,8 +40,8 @@ function convert(
   const payto_uris = accounts.filter((a) => a.active).map((a) => a.payto_uri);
   const defaults = {
     default_wire_fee_amortization: 1,
-    default_pay_delay: { d_us: 1000 * 60 * 60 }, //one hour
-    default_wire_transfer_delay: { d_us: 1000 * 60 * 60 * 2 }, //two hours
+    default_pay_delay: { d_us: 1000 * 60 * 60 * 1000 }, //one hour
+    default_wire_transfer_delay: { d_us: 1000 * 60 * 60 * 2 * 1000 }, //two 
hours
   };
   return { ...defaults, ...rest, payto_uris };
 }
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 cdbe732a4..3a6e0fbfe 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/details/stories.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/details/stories.tsx
@@ -59,11 +59,11 @@ export const Example = createExample(TestedComponent, {
     default_max_deposit_fee: "TESTKUDOS:2",
     default_max_wire_fee: "TESTKUDOS:1",
     default_pay_delay: {
-      d_us: 1000000,
+      d_us: 1000 * 1000, //one second
     },
     default_wire_fee_amortization: 1,
     default_wire_transfer_delay: {
-      d_us: 100000,
+      d_us: 1000 * 1000, //one second
     },
     merchant_pub: "ASDWQEKASJDKSADJ",
   },
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/Create.stories.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/Create.stories.tsx
index 5f8dbbdd9..fcf611c3c 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/Create.stories.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/Create.stories.tsx
@@ -45,7 +45,7 @@ export const Example = createExample(TestedComponent, {
     default_max_deposit_fee: "",
     default_max_wire_fee: "",
     default_pay_delay: {
-      d_us: 1000 * 60 * 60,
+      d_us: 1000 * 1000 * 60 * 60, //one hour
     },
     default_wire_fee_amortization: 1,
   },
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx
index 0c2e92418..f4a82f377 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx
@@ -61,7 +61,9 @@ function with_defaults(config: InstanceConfig): 
Partial<Entity> {
   const defaultPayDeadline =
     !config.default_pay_delay || config.default_pay_delay.d_us === "forever"
       ? undefined
-      : add(new Date(), { seconds: config.default_pay_delay.d_us / 1000 });
+      : add(new Date(), {
+          seconds: config.default_pay_delay.d_us / (1000 * 1000),
+        });
 
   return {
     inventoryProducts: {},
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 2a47c22a0..2b8d718fb 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
@@ -72,7 +72,7 @@ export function CreatePage({ onCreate, onBack }: Props): 
VNode {
             ? i18n.str`can't be empty`
             : state.template_contract.pay_duration.d_us === "forever"
             ? undefined
-            : state.template_contract.pay_duration.d_us < 1000
+            : state.template_contract.pay_duration.d_us < 1000 * 1000 //less 
than one second
             ? i18n.str`to short`
             : undefined,
         }),
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/ListPage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/ListPage.tsx
index 9d289e957..8482f7f52 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/ListPage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/ListPage.tsx
@@ -31,6 +31,7 @@ export interface Props {
   onCreate: () => void;
   onDelete: (e: MerchantBackend.Template.TemplateEntry) => void;
   onSelect: (e: MerchantBackend.Template.TemplateEntry) => void;
+  onNewOrder: (e: MerchantBackend.Template.TemplateEntry) => void;
 }
 
 export function ListPage({
@@ -38,6 +39,7 @@ export function ListPage({
   onCreate,
   onDelete,
   onSelect,
+  onNewOrder,
   onLoadMoreBefore,
   onLoadMoreAfter,
 }: Props): VNode {
@@ -54,6 +56,7 @@ export function ListPage({
         onCreate={onCreate}
         onDelete={onDelete}
         onSelect={onSelect}
+        onNewOrder={onNewOrder}
         onLoadMoreBefore={onLoadMoreBefore}
         hasMoreBefore={!onLoadMoreBefore}
         onLoadMoreAfter={onLoadMoreAfter}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/Table.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/Table.tsx
index fd6ea5f6f..57d328d39 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/Table.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/Table.tsx
@@ -30,6 +30,7 @@ interface Props {
   templates: Entity[];
   onDelete: (e: Entity) => void;
   onSelect: (e: Entity) => void;
+  onNewOrder: (e: Entity) => void;
   onCreate: () => void;
   onLoadMoreBefore?: () => void;
   hasMoreBefore?: boolean;
@@ -42,6 +43,7 @@ export function CardTable({
   onCreate,
   onDelete,
   onSelect,
+  onNewOrder,
   onLoadMoreAfter,
   onLoadMoreBefore,
   hasMoreAfter,
@@ -81,6 +83,7 @@ export function CardTable({
                 instances={templates}
                 onDelete={onDelete}
                 onSelect={onSelect}
+                onNewOrder={onNewOrder}
                 rowSelection={rowSelection}
                 rowSelectionHandler={rowSelectionHandler}
                 onLoadMoreAfter={onLoadMoreAfter}
@@ -101,6 +104,7 @@ interface TableProps {
   rowSelection: string[];
   instances: Entity[];
   onDelete: (e: Entity) => void;
+  onNewOrder: (e: Entity) => void;
   onSelect: (e: Entity) => void;
   rowSelectionHandler: StateUpdater<string[]>;
   onLoadMoreBefore?: () => void;
@@ -118,6 +122,7 @@ function Table({
   instances,
   onLoadMoreAfter,
   onDelete,
+  onNewOrder,
   onSelect,
   onLoadMoreBefore,
   hasMoreAfter,
@@ -164,14 +169,23 @@ function Table({
                 >
                   {i.template_description}
                 </td>
-                <td>
-                  <button
-                    class="button is-danger is-small has-tooltip-left"
-                    data-tooltip={i18n.str`delete selected templates from the 
database`}
-                    onClick={() => onDelete(i)}
-                  >
-                    Delete
-                  </button>
+                <td class="is-actions-cell right-sticky">
+                  <div class="buttons is-right">
+                    <button
+                      class="button is-danger is-small has-tooltip-left"
+                      data-tooltip={i18n.str`delete selected templates from 
the database`}
+                      onClick={() => onDelete(i)}
+                    >
+                      Delete
+                    </button>
+                    <button
+                      class="button is-info is-small has-tooltip-left"
+                      data-tooltip={i18n.str`use template to create new order`}
+                      onClick={() => onNewOrder(i)}
+                    >
+                      New order
+                    </button>
+                  </div>
                 </td>
               </tr>
             );
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 e1a2d019e..5fce3a819 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
@@ -39,6 +39,7 @@ interface Props {
   onNotFound: () => VNode;
   onCreate: () => void;
   onSelect: (id: string) => void;
+  onNewOrder: (id: string) => void;
 }
 
 export default function ListTemplates({
@@ -46,6 +47,7 @@ export default function ListTemplates({
   onLoadError,
   onCreate,
   onSelect,
+  onNewOrder,
   onNotFound,
 }: Props): VNode {
   const [position, setPosition] = useState<string | undefined>(undefined);
@@ -73,6 +75,9 @@ export default function ListTemplates({
         onSelect={(e) => {
           onSelect(e.template_id);
         }}
+        onNewOrder={(e) => {
+          onNewOrder(e.template_id);
+        }}
         onDelete={(e: MerchantBackend.Template.TemplateEntry) =>
           deleteTemplate(e.template_id)
             .then(() =>
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 a49e8000b..718a67ae0 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
@@ -65,7 +65,7 @@ export function UpdatePage({ template, onUpdate, onBack }: 
Props): VNode {
             ? i18n.str`can't be empty`
             : state.template_contract.pay_duration.d_us === "forever"
             ? undefined
-            : state.template_contract.pay_duration.d_us < 1000
+            : state.template_contract.pay_duration.d_us < 1000 * 1000 // less 
than one second
             ? i18n.str`to short`
             : undefined,
         }),
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/Create.stories.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/Use.stories.tsx
similarity index 93%
copy from 
packages/merchant-backoffice-ui/src/paths/instance/templates/create/Create.stories.tsx
copy to 
packages/merchant-backoffice-ui/src/paths/instance/templates/use/Use.stories.tsx
index c9d17ea3b..f073b4235 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/Create.stories.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/Use.stories.tsx
@@ -20,7 +20,7 @@
  */
 
 import { h, VNode, FunctionalComponent } from "preact";
-import { CreatePage as TestedComponent } from "./CreatePage.js";
+import { CreatePage as TestedComponent } from "./UsePage.js";
 
 export default {
   title: "Pages/Templates/Create",
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/CreatePage.tsx
 b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/UsePage.tsx
similarity index 55%
copy from 
packages/merchant-backoffice-ui/src/paths/instance/transfers/create/CreatePage.tsx
copy to 
packages/merchant-backoffice-ui/src/paths/instance/templates/use/UsePage.tsx
index 5303d14d9..a63469763 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/CreatePage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/UsePage.tsx
@@ -29,48 +29,33 @@ import {
 } from "../../../../components/form/FormProvider.js";
 import { Input } from "../../../../components/form/Input.js";
 import { InputCurrency } from "../../../../components/form/InputCurrency.js";
-import { InputSelector } from "../../../../components/form/InputSelector.js";
-import { useConfigContext } from "../../../../context/config.js";
 import { MerchantBackend } from "../../../../declaration.js";
-import {
-  CROCKFORD_BASE32_REGEX,
-  URL_REGEX,
-} from "../../../../utils/constants.js";
 
-type Entity = MerchantBackend.Transfers.TransferInformation;
+type Entity = MerchantBackend.Template.UsingTemplateDetails;
 
 interface Props {
-  onCreate: (d: Entity) => Promise<void>;
+  template: MerchantBackend.Template.TemplateDetails;
+  onCreateOrder: (d: Entity) => Promise<void>;
   onBack?: () => void;
-  accounts: string[];
 }
 
-export function CreatePage({ accounts, onCreate, onBack }: Props): VNode {
+export function UsePage({ template, onCreateOrder, onBack }: Props): VNode {
   const { i18n } = useTranslationContext();
-  const { currency } = useConfigContext();
 
   const [state, setState] = useState<Partial<Entity>>({
-    wtid: "",
-    // payto_uri: ,
-    // exchange_url: 'http://exchange.taler:8081/',
-    credit_amount: ``,
+    amount: template.template_contract.amount,
+    summary: template.template_contract.summary,
   });
 
   const errors: FormErrors<Entity> = {
-    wtid: !state.wtid
-      ? i18n.str`cannot be empty`
-      : !CROCKFORD_BASE32_REGEX.test(state.wtid)
-      ? i18n.str`check the id, does not look valid`
-      : state.wtid.length !== 52
-      ? i18n.str`should have 52 characters, current ${state.wtid.length}`
-      : undefined,
-    payto_uri: !state.payto_uri ? i18n.str`cannot be empty` : undefined,
-    credit_amount: !state.credit_amount ? i18n.str`cannot be empty` : 
undefined,
-    exchange_url: !state.exchange_url
-      ? i18n.str`cannot be empty`
-      : !URL_REGEX.test(state.exchange_url)
-      ? i18n.str`URL doesn't have the right format`
-      : undefined,
+    amount:
+      !template.template_contract.amount && !state.amount
+        ? i18n.str`Amount is required`
+        : undefined,
+    summary:
+      !template.template_contract.summary && !state.summary
+        ? i18n.str`Order summary is required`
+        : undefined,
   };
 
   const hasErrors = Object.keys(errors).some(
@@ -79,7 +64,13 @@ export function CreatePage({ accounts, onCreate, onBack }: 
Props): VNode {
 
   const submitForm = () => {
     if (hasErrors) return Promise.reject();
-    return onCreate(state as any);
+    if (template.template_contract.amount) {
+      delete state.amount;
+    }
+    if (template.template_contract.summary) {
+      delete state.summary;
+    }
+    return onCreateOrder(state as any);
   };
 
   return (
@@ -93,29 +84,18 @@ export function CreatePage({ accounts, onCreate, onBack }: 
Props): VNode {
               valueHandler={setState}
               errors={errors}
             >
-              <InputSelector
-                name="payto_uri"
-                label={i18n.str`Credited bank account`}
-                values={accounts}
-                placeholder={i18n.str`Select one account`}
-                tooltip={i18n.str`Bank account of the merchant where the 
payment was received`}
-              />
-              <Input<Entity>
-                name="wtid"
-                label={i18n.str`Wire transfer ID`}
-                help=""
-                tooltip={i18n.str`unique identifier of the wire transfer used 
by the exchange, must be 52 characters long`}
+              <InputCurrency<Entity>
+                name="amount"
+                label={i18n.str`Amount`}
+                readonly={!!template.template_contract.amount}
+                tooltip={i18n.str`Amount of the order`}
               />
               <Input<Entity>
-                name="exchange_url"
-                label={i18n.str`Exchange URL`}
-                tooltip={i18n.str`Base URL of the exchange that made the 
transfer, should have been in the wire transfer subject`}
-                help="http://exchange.taler:8081/";
-              />
-              <InputCurrency<Entity>
-                name="credit_amount"
-                label={i18n.str`Amount credited`}
-                tooltip={i18n.str`Actual amount that was wired to the 
merchant's bank account`}
+                name="summary"
+                inputType="multiline"
+                label={i18n.str`Order summary`}
+                readonly={!!template.template_contract.summary}
+                tooltip={i18n.str`Title of the order to be shown to the 
customer`}
               />
             </FormProvider>
 
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx
similarity index 76%
copy from 
packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx
copy to 
packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx
index 684ffd429..fa9a98c6d 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx
@@ -24,37 +24,36 @@ import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { Loading } from "../../../../components/exception/loading.js";
 import { NotificationCard } from "../../../../components/menu/index.js";
-import { MerchantBackend, WithId } from "../../../../declaration.js";
-import { HttpError } from "../../../../utils/request.js";
+import { MerchantBackend } from "../../../../declaration.js";
 import {
   useTemplateAPI,
   useTemplateDetails,
 } from "../../../../hooks/templates.js";
+import { HttpError } from "../../../../utils/request.js";
 import { Notification } from "../../../../utils/types.js";
-import { UpdatePage } from "./UpdatePage.js";
-
-export type Entity = MerchantBackend.Template.TemplatePatchDetails & WithId;
+import { UsePage } from "./UsePage.js";
 
+export type Entity = MerchantBackend.Transfers.TransferInformation;
 interface Props {
   onBack?: () => void;
-  onConfirm: () => void;
+  onOrderCreated: (id: string) => void;
   onUnauthorized: () => VNode;
   onNotFound: () => VNode;
   onLoadError: (e: HttpError) => VNode;
   tid: string;
 }
-export default function UpdateTemplate({
+
+export default function TemplateUsePage({
   tid,
-  onConfirm,
+  onOrderCreated,
   onBack,
-  onUnauthorized,
-  onNotFound,
   onLoadError,
+  onNotFound,
+  onUnauthorized,
 }: Props): VNode {
-  const { updateTemplate } = useTemplateAPI();
+  const { createOrderFromTemplate } = useTemplateAPI();
   const result = useTemplateDetails(tid);
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
-
   const { i18n } = useTranslationContext();
 
   if (result.clientError && result.isUnauthorized) return onUnauthorized();
@@ -63,23 +62,25 @@ export default function UpdateTemplate({
   if (!result.ok) return onLoadError(result);
 
   return (
-    <Fragment>
+    <>
       <NotificationCard notification={notif} />
-      <UpdatePage
-        template={{ ...result.data, id: tid }}
+      <UsePage
+        template={result.data}
         onBack={onBack}
-        onUpdate={(data) => {
-          return updateTemplate(tid, data)
-            .then(onConfirm)
+        onCreateOrder={(
+          request: MerchantBackend.Template.UsingTemplateDetails,
+        ) => {
+          return createOrderFromTemplate(tid, request)
+            .then((res) => onOrderCreated(res.data.order_id))
             .catch((error) => {
               setNotif({
-                message: i18n.str`could not update template`,
+                message: i18n.str`could not create order from template`,
                 type: "ERROR",
                 description: error.message,
               });
             });
         }}
       />
-    </Fragment>
+    </>
   );
 }
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/update/Update.stories.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/update/Update.stories.tsx
index 58b8d87ea..045c96c2c 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/update/Update.stories.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/update/Update.stories.tsx
@@ -50,11 +50,11 @@ export const Example = createExample(TestedComponent, {
     default_max_deposit_fee: "TESTKUDOS:2",
     default_max_wire_fee: "TESTKUDOS:1",
     default_pay_delay: {
-      d_us: 1000000,
+      d_us: 1000 * 1000, //one second
     },
     default_wire_fee_amortization: 1,
     default_wire_transfer_delay: {
-      d_us: 100000,
+      d_us: 1000 * 1000, //one second
     },
     merchant_pub: "ASDWQEKASJDKSADJ",
   },
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/Create.stories.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/Create.stories.tsx
similarity index 96%
copy from 
packages/merchant-backoffice-ui/src/paths/instance/templates/create/Create.stories.tsx
copy to 
packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/Create.stories.tsx
index c9d17ea3b..4857ede97 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/Create.stories.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/Create.stories.tsx
@@ -23,6 +23,6 @@ import { h, VNode, FunctionalComponent } from "preact";
 import { CreatePage as TestedComponent } from "./CreatePage.js";
 
 export default {
-  title: "Pages/Templates/Create",
+  title: "Pages/Webhooks/Create",
   component: TestedComponent,
 };
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/CreatePage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/CreatePage.tsx
similarity index 56%
copy from 
packages/merchant-backoffice-ui/src/paths/instance/transfers/create/CreatePage.tsx
copy to 
packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/CreatePage.tsx
index 5303d14d9..1d049149b 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/CreatePage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/CreatePage.tsx
@@ -29,48 +29,34 @@ import {
 } from "../../../../components/form/FormProvider.js";
 import { Input } from "../../../../components/form/Input.js";
 import { InputCurrency } from "../../../../components/form/InputCurrency.js";
-import { InputSelector } from "../../../../components/form/InputSelector.js";
-import { useConfigContext } from "../../../../context/config.js";
+import { InputDuration } from "../../../../components/form/InputDuration.js";
+import { InputNumber } from "../../../../components/form/InputNumber.js";
+import { useBackendContext } from "../../../../context/backend.js";
 import { MerchantBackend } from "../../../../declaration.js";
-import {
-  CROCKFORD_BASE32_REGEX,
-  URL_REGEX,
-} from "../../../../utils/constants.js";
 
-type Entity = MerchantBackend.Transfers.TransferInformation;
+type Entity = MerchantBackend.Webhooks.WebhookAddDetails;
 
 interface Props {
   onCreate: (d: Entity) => Promise<void>;
   onBack?: () => void;
-  accounts: string[];
 }
 
-export function CreatePage({ accounts, onCreate, onBack }: Props): VNode {
+const validMethod = ["GET", "POST", "PUT", "PATCH", "HEAD"];
+
+export function CreatePage({ onCreate, onBack }: Props): VNode {
   const { i18n } = useTranslationContext();
-  const { currency } = useConfigContext();
 
-  const [state, setState] = useState<Partial<Entity>>({
-    wtid: "",
-    // payto_uri: ,
-    // exchange_url: 'http://exchange.taler:8081/',
-    credit_amount: ``,
-  });
+  const [state, setState] = useState<Partial<Entity>>({});
 
   const errors: FormErrors<Entity> = {
-    wtid: !state.wtid
-      ? i18n.str`cannot be empty`
-      : !CROCKFORD_BASE32_REGEX.test(state.wtid)
-      ? i18n.str`check the id, does not look valid`
-      : state.wtid.length !== 52
-      ? i18n.str`should have 52 characters, current ${state.wtid.length}`
-      : undefined,
-    payto_uri: !state.payto_uri ? i18n.str`cannot be empty` : undefined,
-    credit_amount: !state.credit_amount ? i18n.str`cannot be empty` : 
undefined,
-    exchange_url: !state.exchange_url
-      ? i18n.str`cannot be empty`
-      : !URL_REGEX.test(state.exchange_url)
-      ? i18n.str`URL doesn't have the right format`
+    webhook_id: !state.webhook_id ? i18n.str`required` : undefined,
+    event_type: !state.event_type ? i18n.str`required` : undefined,
+    http_method: !state.http_method
+      ? i18n.str`required`
+      : !validMethod.includes(state.http_method)
+      ? i18n.str`should be one of "${validMethod.join(", ")}"`
       : undefined,
+    url: !state.url ? i18n.str`required` : undefined,
   };
 
   const hasErrors = Object.keys(errors).some(
@@ -93,29 +79,37 @@ export function CreatePage({ accounts, onCreate, onBack }: 
Props): VNode {
               valueHandler={setState}
               errors={errors}
             >
-              <InputSelector
-                name="payto_uri"
-                label={i18n.str`Credited bank account`}
-                values={accounts}
-                placeholder={i18n.str`Select one account`}
-                tooltip={i18n.str`Bank account of the merchant where the 
payment was received`}
+              <Input<Entity>
+                name="webhook_id"
+                label={i18n.str`ID`}
+                tooltip={i18n.str`Webhook ID to use`}
               />
               <Input<Entity>
-                name="wtid"
-                label={i18n.str`Wire transfer ID`}
-                help=""
-                tooltip={i18n.str`unique identifier of the wire transfer used 
by the exchange, must be 52 characters long`}
+                name="event_type"
+                label={i18n.str`Event`}
+                tooltip={i18n.str`The event of the webhook: why the webhook is 
used`}
               />
               <Input<Entity>
-                name="exchange_url"
-                label={i18n.str`Exchange URL`}
-                tooltip={i18n.str`Base URL of the exchange that made the 
transfer, should have been in the wire transfer subject`}
-                help="http://exchange.taler:8081/";
+                name="http_method"
+                label={i18n.str`Method`}
+                tooltip={i18n.str`Method used by the webhook`}
               />
-              <InputCurrency<Entity>
-                name="credit_amount"
-                label={i18n.str`Amount credited`}
-                tooltip={i18n.str`Actual amount that was wired to the 
merchant's bank account`}
+              <Input<Entity>
+                name="url"
+                label={i18n.str`URL`}
+                tooltip={i18n.str`URL of the webhook where the customer will 
be redirected`}
+              />
+              <Input<Entity>
+                name="header_template"
+                label={i18n.str`Header`}
+                inputType="multiline"
+                tooltip={i18n.str`Header template of the webhook`}
+              />
+              <Input<Entity>
+                name="body_template"
+                inputType="multiline"
+                label={i18n.str`Body`}
+                tooltip={i18n.str`Body template by the webhook`}
               />
             </FormProvider>
 
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx
similarity index 82%
copy from 
packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx
copy to 
packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx
index dcbf70106..9f1c5e905 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx
@@ -24,18 +24,18 @@ import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { NotificationCard } from "../../../../components/menu/index.js";
 import { MerchantBackend } from "../../../../declaration.js";
-import { useTemplateAPI } from "../../../../hooks/templates.js";
+import { useWebhookAPI } from "../../../../hooks/webhooks.js";
 import { Notification } from "../../../../utils/types.js";
 import { CreatePage } from "./CreatePage.js";
 
-export type Entity = MerchantBackend.Transfers.TransferInformation;
+export type Entity = MerchantBackend.Webhooks.WebhookAddDetails;
 interface Props {
   onBack?: () => void;
   onConfirm: () => void;
 }
 
-export default function CreateTransfer({ onConfirm, onBack }: Props): VNode {
-  const { createTemplate } = useTemplateAPI();
+export default function CreateWebhook({ onConfirm, onBack }: Props): VNode {
+  const { createWebhook } = useWebhookAPI();
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
   const { i18n } = useTranslationContext();
 
@@ -44,8 +44,8 @@ export default function CreateTransfer({ onConfirm, onBack }: 
Props): VNode {
       <NotificationCard notification={notif} />
       <CreatePage
         onBack={onBack}
-        onCreate={(request: MerchantBackend.Template.TemplateAddDetails) => {
-          return createTemplate(request)
+        onCreate={(request: MerchantBackend.Webhooks.WebhookAddDetails) => {
+          return createWebhook(request)
             .then(() => onConfirm())
             .catch((error) => {
               setNotif({
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/List.stories.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/List.stories.tsx
similarity index 100%
copy from 
packages/merchant-backoffice-ui/src/paths/instance/templates/list/List.stories.tsx
copy to 
packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/List.stories.tsx
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/ListPage.tsx
 b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/ListPage.tsx
similarity index 85%
copy from 
packages/merchant-backoffice-ui/src/paths/instance/templates/list/ListPage.tsx
copy to 
packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/ListPage.tsx
index 9d289e957..942a8a63e 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/ListPage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/ListPage.tsx
@@ -25,16 +25,16 @@ import { useTranslationContext } from 
"@gnu-taler/web-util/lib/index.browser";
 import { CardTable } from "./Table.js";
 
 export interface Props {
-  templates: MerchantBackend.Template.TemplateEntry[];
+  webhooks: MerchantBackend.Webhooks.WebhookEntry[];
   onLoadMoreBefore?: () => void;
   onLoadMoreAfter?: () => void;
   onCreate: () => void;
-  onDelete: (e: MerchantBackend.Template.TemplateEntry) => void;
-  onSelect: (e: MerchantBackend.Template.TemplateEntry) => void;
+  onDelete: (e: MerchantBackend.Webhooks.WebhookEntry) => void;
+  onSelect: (e: MerchantBackend.Webhooks.WebhookEntry) => void;
 }
 
 export function ListPage({
-  templates,
+  webhooks,
   onCreate,
   onDelete,
   onSelect,
@@ -47,9 +47,9 @@ export function ListPage({
   return (
     <section class="section is-main-section">
       <CardTable
-        templates={templates.map((o) => ({
+        webhooks={webhooks.map((o) => ({
           ...o,
-          id: String(o.template_id),
+          id: String(o.webhook_id),
         }))}
         onCreate={onCreate}
         onDelete={onDelete}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/Table.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/Table.tsx
similarity index 75%
copy from 
packages/merchant-backoffice-ui/src/paths/instance/templates/list/Table.tsx
copy to 
packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/Table.tsx
index fd6ea5f6f..1981cabdd 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/Table.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/Table.tsx
@@ -24,10 +24,10 @@ import { h, VNode } from "preact";
 import { StateUpdater, useState } from "preact/hooks";
 import { MerchantBackend } from "../../../../declaration.js";
 
-type Entity = MerchantBackend.Template.TemplateEntry;
+type Entity = MerchantBackend.Webhooks.WebhookEntry;
 
 interface Props {
-  templates: Entity[];
+  webhooks: Entity[];
   onDelete: (e: Entity) => void;
   onSelect: (e: Entity) => void;
   onCreate: () => void;
@@ -38,7 +38,7 @@ interface Props {
 }
 
 export function CardTable({
-  templates,
+  webhooks,
   onCreate,
   onDelete,
   onSelect,
@@ -58,12 +58,12 @@ export function CardTable({
           <span class="icon">
             <i class="mdi mdi-newspaper" />
           </span>
-          <i18n.Translate>Templates</i18n.Translate>
+          <i18n.Translate>Webhooks</i18n.Translate>
         </p>
         <div class="card-header-icon" aria-label="more options">
           <span
             class="has-tooltip-left"
-            data-tooltip={i18n.str`add new templates`}
+            data-tooltip={i18n.str`add new webhooks`}
           >
             <button class="button is-info" type="button" onClick={onCreate}>
               <span class="icon is-small">
@@ -76,11 +76,14 @@ export function CardTable({
       <div class="card-content">
         <div class="b-table has-pagination">
           <div class="table-wrapper has-mobile-cards">
-            {templates.length > 0 ? (
+            {webhooks.length > 0 ? (
               <Table
-                instances={templates}
+                instances={webhooks}
                 onDelete={onDelete}
                 onSelect={onSelect}
+                onNewOrder={(d) => {
+                  console.log("test", d);
+                }}
                 rowSelection={rowSelection}
                 rowSelectionHandler={rowSelectionHandler}
                 onLoadMoreAfter={onLoadMoreAfter}
@@ -101,6 +104,7 @@ interface TableProps {
   rowSelection: string[];
   instances: Entity[];
   onDelete: (e: Entity) => void;
+  onNewOrder: (e: Entity) => void;
   onSelect: (e: Entity) => void;
   rowSelectionHandler: StateUpdater<string[]>;
   onLoadMoreBefore?: () => void;
@@ -118,6 +122,7 @@ function Table({
   instances,
   onLoadMoreAfter,
   onDelete,
+  onNewOrder,
   onSelect,
   onLoadMoreBefore,
   hasMoreAfter,
@@ -129,11 +134,11 @@ function Table({
       {onLoadMoreBefore && (
         <button
           class="button is-fullwidth"
-          data-tooltip={i18n.str`load more templates before the first one`}
+          data-tooltip={i18n.str`load more webhooks before the first one`}
           disabled={!hasMoreBefore}
           onClick={onLoadMoreBefore}
         >
-          <i18n.Translate>load newer templates</i18n.Translate>
+          <i18n.Translate>load newer webhooks</i18n.Translate>
         </button>
       )}
       <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
@@ -143,7 +148,7 @@ function Table({
               <i18n.Translate>ID</i18n.Translate>
             </th>
             <th>
-              <i18n.Translate>Description</i18n.Translate>
+              <i18n.Translate>Event type</i18n.Translate>
             </th>
             <th />
           </tr>
@@ -151,27 +156,36 @@ function Table({
         <tbody>
           {instances.map((i) => {
             return (
-              <tr key={i.template_id}>
+              <tr key={i.webhook_id}>
                 <td
                   onClick={(): void => onSelect(i)}
                   style={{ cursor: "pointer" }}
                 >
-                  {i.template_id}
+                  {i.webhook_id}
                 </td>
                 <td
                   onClick={(): void => onSelect(i)}
                   style={{ cursor: "pointer" }}
                 >
-                  {i.template_description}
+                  {i.event_type}
                 </td>
-                <td>
-                  <button
-                    class="button is-danger is-small has-tooltip-left"
-                    data-tooltip={i18n.str`delete selected templates from the 
database`}
-                    onClick={() => onDelete(i)}
-                  >
-                    Delete
-                  </button>
+                <td class="is-actions-cell right-sticky">
+                  <div class="buttons is-right">
+                    <button
+                      class="button is-danger is-small has-tooltip-left"
+                      data-tooltip={i18n.str`delete selected webhook from the 
database`}
+                      onClick={() => onDelete(i)}
+                    >
+                      Delete
+                    </button>
+                    {/* <button
+                      class="button is-info is-small has-tooltip-left"
+                      data-tooltip={i18n.str`test webhook`}
+                      onClick={() => onNewOrder(i)}
+                    >
+                      Test
+                    </button> */}
+                  </div>
                 </td>
               </tr>
             );
@@ -181,11 +195,11 @@ function Table({
       {onLoadMoreAfter && (
         <button
           class="button is-fullwidth"
-          data-tooltip={i18n.str`load more templates after the last one`}
+          data-tooltip={i18n.str`load more webhooks after the last one`}
           disabled={!hasMoreAfter}
           onClick={onLoadMoreAfter}
         >
-          <i18n.Translate>load older templates</i18n.Translate>
+          <i18n.Translate>load older webhooks</i18n.Translate>
         </button>
       )}
     </div>
@@ -203,7 +217,7 @@ function EmptyTable(): VNode {
       </p>
       <p>
         <i18n.Translate>
-          There is no templates yet, add more pressing the + sign
+          There is no webhooks yet, add more pressing the + sign
         </i18n.Translate>
       </p>
     </div>
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx
similarity index 82%
copy from 
packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx
copy to 
packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx
index e1a2d019e..c5846e4db 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx
@@ -25,11 +25,11 @@ import { useState } from "preact/hooks";
 import { Loading } from "../../../../components/exception/loading.js";
 import { NotificationCard } from "../../../../components/menu/index.js";
 import { MerchantBackend } from "../../../../declaration.js";
-import { HttpError } from "../../../../utils/request.js";
 import {
-  useInstanceTemplates,
-  useTemplateAPI,
-} from "../../../../hooks/templates.js";
+  useInstanceWebhooks,
+  useWebhookAPI,
+} from "../../../../hooks/webhooks.js";
+import { HttpError } from "../../../../utils/request.js";
 import { Notification } from "../../../../utils/types.js";
 import { ListPage } from "./ListPage.js";
 
@@ -41,7 +41,7 @@ interface Props {
   onSelect: (id: string) => void;
 }
 
-export default function ListTemplates({
+export default function ListWebhooks({
   onUnauthorized,
   onLoadError,
   onCreate,
@@ -51,8 +51,8 @@ export default function ListTemplates({
   const [position, setPosition] = useState<string | undefined>(undefined);
   const { i18n } = useTranslationContext();
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
-  const { deleteTemplate } = useTemplateAPI();
-  const result = useInstanceTemplates({ position }, (id) => setPosition(id));
+  const { deleteWebhook } = useWebhookAPI();
+  const result = useInstanceWebhooks({ position }, (id) => setPosition(id));
 
   if (result.clientError && result.isUnauthorized) return onUnauthorized();
   if (result.clientError && result.isNotfound) return onNotFound();
@@ -64,26 +64,26 @@ export default function ListTemplates({
       <NotificationCard notification={notif} />
 
       <ListPage
-        templates={result.data.templates}
+        webhooks={result.data.webhooks}
         onLoadMoreBefore={
           result.isReachingStart ? result.loadMorePrev : undefined
         }
         onLoadMoreAfter={result.isReachingEnd ? result.loadMore : undefined}
         onCreate={onCreate}
         onSelect={(e) => {
-          onSelect(e.template_id);
+          onSelect(e.webhook_id);
         }}
-        onDelete={(e: MerchantBackend.Template.TemplateEntry) =>
-          deleteTemplate(e.template_id)
+        onDelete={(e: MerchantBackend.Webhooks.WebhookEntry) =>
+          deleteWebhook(e.webhook_id)
             .then(() =>
               setNotif({
-                message: i18n.str`template delete successfully`,
+                message: i18n.str`webhook delete successfully`,
                 type: "SUCCESS",
               }),
             )
             .catch((error) =>
               setNotif({
-                message: i18n.str`could not delete the template`,
+                message: i18n.str`could not delete the webhook`,
                 type: "ERROR",
                 description: error.message,
               }),
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/Update.stories.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/Update.stories.tsx
similarity index 100%
copy from 
packages/merchant-backoffice-ui/src/paths/instance/templates/update/Update.stories.tsx
copy to 
packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/Update.stories.tsx
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/UpdatePage.tsx
similarity index 54%
copy from 
packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
copy to 
packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/UpdatePage.tsx
index a49e8000b..4e3674dca 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/UpdatePage.tsx
@@ -28,47 +28,31 @@ import {
   FormProvider,
 } from "../../../../components/form/FormProvider.js";
 import { Input } from "../../../../components/form/Input.js";
-import { InputCurrency } from "../../../../components/form/InputCurrency.js";
-import { InputDuration } from "../../../../components/form/InputDuration.js";
-import { InputNumber } from "../../../../components/form/InputNumber.js";
-import { InputWithAddon } from "../../../../components/form/InputWithAddon.js";
 import { useBackendContext } from "../../../../context/backend.js";
 import { MerchantBackend, WithId } from "../../../../declaration.js";
-import { undefinedIfEmpty } from "../../../../utils/table.js";
 
-type Entity = MerchantBackend.Template.TemplatePatchDetails & WithId;
+type Entity = MerchantBackend.Webhooks.WebhookPatchDetails & WithId;
 
 interface Props {
   onUpdate: (d: Entity) => Promise<void>;
   onBack?: () => void;
-  template: Entity;
+  webhook: Entity;
 }
+const validMethod = ["GET", "POST", "PUT", "PATCH", "HEAD"];
 
-export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
+export function UpdatePage({ webhook, onUpdate, onBack }: Props): VNode {
   const { i18n } = useTranslationContext();
-  const backend = useBackendContext();
 
-  const [state, setState] = useState<Partial<Entity>>(template);
+  const [state, setState] = useState<Partial<Entity>>(webhook);
 
   const errors: FormErrors<Entity> = {
-    template_description: !state.template_description
-      ? i18n.str`should not be empty`
+    event_type: !state.event_type ? i18n.str`required` : undefined,
+    http_method: !state.http_method
+      ? i18n.str`required`
+      : !validMethod.includes(state.http_method)
+      ? i18n.str`should be one of "${validMethod.join(", ")}"`
       : undefined,
-    template_contract: !state.template_contract
-      ? undefined
-      : undefinedIfEmpty({
-          minimum_age:
-            state.template_contract.minimum_age < 0
-              ? i18n.str`should be greater that 0`
-              : undefined,
-          pay_duration: !state.template_contract.pay_duration
-            ? i18n.str`can't be empty`
-            : state.template_contract.pay_duration.d_us === "forever"
-            ? undefined
-            : state.template_contract.pay_duration.d_us < 1000
-            ? i18n.str`to short`
-            : undefined,
-        }),
+    url: !state.url ? i18n.str`required` : undefined,
   };
 
   const hasErrors = Object.keys(errors).some(
@@ -89,7 +73,7 @@ export function UpdatePage({ template, onUpdate, onBack }: 
Props): VNode {
               <div class="level-left">
                 <div class="level-item">
                   <span class="is-size-4">
-                    {backend.url}/instances/template/{template.id}
+                    Webhook: <b>{webhook.id}</b>
                   </span>
                 </div>
               </div>
@@ -106,42 +90,32 @@ export function UpdatePage({ template, onUpdate, onBack }: 
Props): VNode {
                 valueHandler={setState}
                 errors={errors}
               >
-                <InputWithAddon<Entity>
-                  name="id"
-                  addonBefore={`templates/`}
-                  readonly
-                  label={i18n.str`Identifier`}
-                  tooltip={i18n.str`Name of the template in URLs.`}
-                />
-
                 <Input<Entity>
-                  name="template_description"
-                  label={i18n.str`Description`}
-                  help=""
-                  tooltip={i18n.str`Describe what this template stands for`}
+                  name="event_type"
+                  label={i18n.str`Event`}
+                  tooltip={i18n.str`The event of the webhook: why the webhook 
is used`}
                 />
-                <Input
-                  name="template_contract.summary"
-                  inputType="multiline"
-                  label={i18n.str`Order summary`}
-                  tooltip={i18n.str`Title of the order to be shown to the 
customer`}
+                <Input<Entity>
+                  name="http_method"
+                  label={i18n.str`Method`}
+                  tooltip={i18n.str`Method used by the webhook`}
                 />
-                <InputCurrency
-                  name="template_contract.amount"
-                  label={i18n.str`Order price`}
-                  tooltip={i18n.str`total product price added up`}
+                <Input<Entity>
+                  name="url"
+                  label={i18n.str`URL`}
+                  tooltip={i18n.str`URL of the webhook where the customer will 
be redirected`}
                 />
-                <InputNumber
-                  name="template_contract.minimum_age"
-                  label={i18n.str`Minimum age`}
-                  help=""
-                  tooltip={i18n.str`Is this contract restricted to some age?`}
+                <Input<Entity>
+                  name="header_template"
+                  label={i18n.str`Header`}
+                  inputType="multiline"
+                  tooltip={i18n.str`Header template of the webhook`}
                 />
-                <InputDuration
-                  name="template_contract.pay_duration"
-                  label={i18n.str`Payment timeout`}
-                  help=""
-                  tooltip={i18n.str`How much time has the customer to complete 
the payment once the order was created.`}
+                <Input<Entity>
+                  name="body_template"
+                  inputType="multiline"
+                  label={i18n.str`Body`}
+                  tooltip={i18n.str`Body template by the webhook`}
                 />
               </FormProvider>
 
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx
similarity index 86%
copy from 
packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx
copy to 
packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx
index 684ffd429..3597fb849 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx
@@ -25,15 +25,15 @@ import { useState } from "preact/hooks";
 import { Loading } from "../../../../components/exception/loading.js";
 import { NotificationCard } from "../../../../components/menu/index.js";
 import { MerchantBackend, WithId } from "../../../../declaration.js";
-import { HttpError } from "../../../../utils/request.js";
 import {
-  useTemplateAPI,
-  useTemplateDetails,
-} from "../../../../hooks/templates.js";
+  useWebhookAPI,
+  useWebhookDetails,
+} from "../../../../hooks/webhooks.js";
+import { HttpError } from "../../../../utils/request.js";
 import { Notification } from "../../../../utils/types.js";
 import { UpdatePage } from "./UpdatePage.js";
 
-export type Entity = MerchantBackend.Template.TemplatePatchDetails & WithId;
+export type Entity = MerchantBackend.Webhooks.WebhookPatchDetails & WithId;
 
 interface Props {
   onBack?: () => void;
@@ -43,7 +43,7 @@ interface Props {
   onLoadError: (e: HttpError) => VNode;
   tid: string;
 }
-export default function UpdateTemplate({
+export default function UpdateWebhook({
   tid,
   onConfirm,
   onBack,
@@ -51,8 +51,8 @@ export default function UpdateTemplate({
   onNotFound,
   onLoadError,
 }: Props): VNode {
-  const { updateTemplate } = useTemplateAPI();
-  const result = useTemplateDetails(tid);
+  const { updateWebhook } = useWebhookAPI();
+  const result = useWebhookDetails(tid);
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
 
   const { i18n } = useTranslationContext();
@@ -66,10 +66,10 @@ export default function UpdateTemplate({
     <Fragment>
       <NotificationCard notification={notif} />
       <UpdatePage
-        template={{ ...result.data, id: tid }}
+        webhook={{ ...result.data, id: tid }}
         onBack={onBack}
         onUpdate={(data) => {
-          return updateTemplate(tid, data)
+          return updateWebhook(tid, data)
             .then(onConfirm)
             .catch((error) => {
               setNotif({

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