diff --git a/lnbits/extensions/lnurlp/lnurl.py b/lnbits/extensions/lnurlp/lnurl.py
index ca17646fe..fc6cc5459 100644
--- a/lnbits/extensions/lnurlp/lnurl.py
+++ b/lnbits/extensions/lnurlp/lnurl.py
@@ -2,6 +2,7 @@ import hashlib
import math
from http import HTTPStatus
from fastapi import FastAPI, Request
+from starlette.exceptions import HTTPException
from lnurl import LnurlPayResponse, LnurlPayActionResponse, LnurlErrorResponse # type: ignore
from lnbits.core.services import create_invoice
diff --git a/lnbits/extensions/usermanager/README.md b/lnbits/extensions/usermanager/README.md
new file mode 100644
index 000000000..b6f306275
--- /dev/null
+++ b/lnbits/extensions/usermanager/README.md
@@ -0,0 +1,26 @@
+# User Manager
+
+## Make and manage users/wallets
+
+To help developers use LNbits to manage their users, the User Manager extension allows the creation and management of users and wallets.
+
+For example, a games developer may be developing a game that needs each user to have their own wallet, LNbits can be included in the developers stack as the user and wallet manager. Or someone wanting to manage their family's wallets (wife, children, parents, etc...) or you want to host a community Lightning Network node and want to manage wallets for the users.
+
+## Usage
+
+1. Click the button "NEW USER" to create a new user\
+ 
+2. Fill the user information\
+ - username
+ - the generated wallet name, user can create other wallets later on
+ - email
+ - set a password
+ 
+3. After creating your user, it will appear in the **Users** section, and a user's wallet in the **Wallets** section.
+4. Next you can share the wallet with the corresponding user\
+ 
+5. If you need to create more wallets for some user, click "NEW WALLET" at the top\
+ 
+ - select the existing user you wish to add the wallet
+ - set a wallet name\
+ 
diff --git a/lnbits/extensions/usermanager/__init__.py b/lnbits/extensions/usermanager/__init__.py
new file mode 100644
index 000000000..f421a15c2
--- /dev/null
+++ b/lnbits/extensions/usermanager/__init__.py
@@ -0,0 +1,25 @@
+import asyncio
+
+from fastapi import APIRouter
+
+from lnbits.db import Database
+from lnbits.helpers import template_renderer
+
+db = Database("ext_usermanager")
+
+usermanager_ext: APIRouter = APIRouter(
+ prefix="/usermanager",
+ tags=["usermanager"]
+ #"usermanager", __name__, static_folder="static", template_folder="templates"
+)
+
+def usermanager_renderer():
+ return template_renderer(
+ [
+ "lnbits/extensions/usermanager/templates",
+ ]
+ )
+
+
+from .views_api import * # noqa
+from .views import * # noqa
diff --git a/lnbits/extensions/usermanager/config.json b/lnbits/extensions/usermanager/config.json
new file mode 100644
index 000000000..7391ec299
--- /dev/null
+++ b/lnbits/extensions/usermanager/config.json
@@ -0,0 +1,6 @@
+{
+ "name": "User Manager",
+ "short_description": "Generate users and wallets",
+ "icon": "person_add",
+ "contributors": ["benarc"]
+}
diff --git a/lnbits/extensions/usermanager/crud.py b/lnbits/extensions/usermanager/crud.py
new file mode 100644
index 000000000..e1c8aebdb
--- /dev/null
+++ b/lnbits/extensions/usermanager/crud.py
@@ -0,0 +1,119 @@
+from typing import Optional, List
+
+from lnbits.core.models import Payment
+from lnbits.core.crud import (
+ create_account,
+ get_user,
+ get_payments,
+ create_wallet,
+ delete_wallet,
+)
+
+from . import db
+from .models import Users, Wallets, CreateUserData
+
+
+### Users
+
+
+async def create_usermanager_user(
+ data: CreateUserData
+) -> Users:
+ account = await create_account()
+ user = await get_user(account.id)
+ assert user, "Newly created user couldn't be retrieved"
+
+ wallet = await create_wallet(user_id=user.id, wallet_name=data.wallet_name)
+
+ await db.execute(
+ """
+ INSERT INTO usermanager.users (id, name, admin, email, password)
+ VALUES (?, ?, ?, ?, ?)
+ """,
+ (user.id, data.user_name, data.admin_id, data.email, data.password),
+ )
+
+ await db.execute(
+ """
+ INSERT INTO usermanager.wallets (id, admin, name, "user", adminkey, inkey)
+ VALUES (?, ?, ?, ?, ?, ?)
+ """,
+ (wallet.id, data.admin_id, data.wallet_name, user.id, wallet.adminkey, wallet.inkey),
+ )
+
+ user_created = await get_usermanager_user(user.id)
+ assert user_created, "Newly created user couldn't be retrieved"
+ return user_created
+
+
+async def get_usermanager_user(user_id: str) -> Optional[Users]:
+ row = await db.fetchone("SELECT * FROM usermanager.users WHERE id = ?", (user_id,))
+ return Users(**row) if row else None
+
+
+async def get_usermanager_users(user_id: str) -> List[Users]:
+ rows = await db.fetchall(
+ "SELECT * FROM usermanager.users WHERE admin = ?", (user_id,)
+ )
+
+ return [Users(**row) for row in rows]
+
+
+async def delete_usermanager_user(user_id: str) -> None:
+ wallets = await get_usermanager_wallets(user_id)
+ for wallet in wallets:
+ await delete_wallet(user_id=user_id, wallet_id=wallet.id)
+
+ await db.execute("DELETE FROM usermanager.users WHERE id = ?", (user_id,))
+ await db.execute("""DELETE FROM usermanager.wallets WHERE "user" = ?""", (user_id,))
+
+
+### Wallets
+
+
+async def create_usermanager_wallet(
+ user_id: str, wallet_name: str, admin_id: str
+) -> Wallets:
+ wallet = await create_wallet(user_id=user_id, wallet_name=wallet_name)
+ await db.execute(
+ """
+ INSERT INTO usermanager.wallets (id, admin, name, "user", adminkey, inkey)
+ VALUES (?, ?, ?, ?, ?, ?)
+ """,
+ (wallet.id, admin_id, wallet_name, user_id, wallet.adminkey, wallet.inkey),
+ )
+ wallet_created = await get_usermanager_wallet(wallet.id)
+ assert wallet_created, "Newly created wallet couldn't be retrieved"
+ return wallet_created
+
+
+async def get_usermanager_wallet(wallet_id: str) -> Optional[Wallets]:
+ row = await db.fetchone(
+ "SELECT * FROM usermanager.wallets WHERE id = ?", (wallet_id,)
+ )
+ return Wallets(**row) if row else None
+
+
+async def get_usermanager_wallets(admin_id: str) -> Optional[Wallets]:
+ rows = await db.fetchall(
+ "SELECT * FROM usermanager.wallets WHERE admin = ?", (admin_id,)
+ )
+ return [Wallets(**row) for row in rows]
+
+
+async def get_usermanager_users_wallets(user_id: str) -> Optional[Wallets]:
+ rows = await db.fetchall(
+ """SELECT * FROM usermanager.wallets WHERE "user" = ?""", (user_id,)
+ )
+ return [Wallets(**row) for row in rows]
+
+
+async def get_usermanager_wallet_transactions(wallet_id: str) -> Optional[Payment]:
+ return await get_payments(
+ wallet_id=wallet_id, complete=True, pending=False, outgoing=True, incoming=True
+ )
+
+
+async def delete_usermanager_wallet(wallet_id: str, user_id: str) -> None:
+ await delete_wallet(user_id=user_id, wallet_id=wallet_id)
+ await db.execute("DELETE FROM usermanager.wallets WHERE id = ?", (wallet_id,))
diff --git a/lnbits/extensions/usermanager/migrations.py b/lnbits/extensions/usermanager/migrations.py
new file mode 100644
index 000000000..62a215752
--- /dev/null
+++ b/lnbits/extensions/usermanager/migrations.py
@@ -0,0 +1,31 @@
+async def m001_initial(db):
+ """
+ Initial users table.
+ """
+ await db.execute(
+ """
+ CREATE TABLE usermanager.users (
+ id TEXT PRIMARY KEY,
+ name TEXT NOT NULL,
+ admin TEXT NOT NULL,
+ email TEXT,
+ password TEXT
+ );
+ """
+ )
+
+ """
+ Initial wallets table.
+ """
+ await db.execute(
+ """
+ CREATE TABLE usermanager.wallets (
+ id TEXT PRIMARY KEY,
+ admin TEXT NOT NULL,
+ name TEXT NOT NULL,
+ "user" TEXT NOT NULL,
+ adminkey TEXT NOT NULL,
+ inkey TEXT NOT NULL
+ );
+ """
+ )
diff --git a/lnbits/extensions/usermanager/models.py b/lnbits/extensions/usermanager/models.py
new file mode 100644
index 000000000..005ed8afb
--- /dev/null
+++ b/lnbits/extensions/usermanager/models.py
@@ -0,0 +1,31 @@
+from pydantic import BaseModel
+from fastapi.param_functions import Query
+from sqlite3 import Row
+
+class CreateUserData(BaseModel):
+ user_name: str = Query(...)
+ wallet_name: str = Query(...)
+ admin_id: str = Query(...)
+ email: str = Query("")
+ password: str = Query("")
+
+
+class Users(BaseModel):
+ id: str
+ name: str
+ admin: str
+ email: str
+ password: str
+
+
+class Wallets(BaseModel):
+ id: str
+ admin: str
+ name: str
+ user: str
+ adminkey: str
+ inkey: str
+
+ @classmethod
+ def from_row(cls, row: Row) -> "Wallets":
+ return cls(**dict(row))
diff --git a/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html b/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html
new file mode 100644
index 000000000..1944416b4
--- /dev/null
+++ b/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html
@@ -0,0 +1,264 @@
+
+ To help developers use LNbits to manage their users, the User Manager
+ extension allows the creation and management of users and wallets.
+
+ User Manager: Make and manager users/wallets
+
+
For example, a games developer may be developing a game that needs
+ each user to have their own wallet, LNbits can be included in the
+ develpoers stack as the user and wallet manager.
+
+ Created by, Ben Arc
+ GET
+ /usermanager/api/v1/users
+ Body (application/json)
+
+ Returns 201 CREATED (application/json)
+
+ JSON list of users
+ Curl example
+ curl -X GET {{ request.url_root }}usermanager/api/v1/users -H
+ "X-Api-Key: {{ user.wallets[0].inkey }}"
+
+ GET
+ /usermanager/api/v1/users/<user_id>
+ Body (application/json)
+
+ Returns 201 CREATED (application/json)
+
+ JSON list of users
+ Curl example
+ curl -X GET {{ request.url_root
+ }}usermanager/api/v1/users/<user_id> -H "X-Api-Key: {{
+ user.wallets[0].inkey }}"
+
+ GET
+ /usermanager/api/v1/wallets/<user_id>
+ Headers
+ {"X-Api-Key": <string>}
+ Body (application/json)
+
+ Returns 201 CREATED (application/json)
+
+ JSON wallet data
+ Curl example
+ curl -X GET {{ request.url_root
+ }}usermanager/api/v1/wallets/<user_id> -H "X-Api-Key: {{
+ user.wallets[0].inkey }}"
+
+ GET
+ /usermanager/api/v1/wallets<wallet_id>
+ Headers
+ {"X-Api-Key": <string>}
+ Body (application/json)
+
+ Returns 201 CREATED (application/json)
+
+ JSON a wallets transactions
+ Curl example
+ curl -X GET {{ request.url_root
+ }}usermanager/api/v1/wallets<wallet_id> -H "X-Api-Key: {{
+ user.wallets[0].inkey }}"
+
+ POST
+ /usermanager/api/v1/users
+ Headers
+ {"X-Api-Key": <string>, "Content-type":
+ "application/json"}
+
+ Body (application/json) - "admin_id" is a YOUR user ID
+
+ {"admin_id": <string>, "user_name": <string>,
+ "wallet_name": <string>,"email": <Optional string>
+ ,"password": <Optional string>}
+
+ Returns 201 CREATED (application/json)
+
+ {"id": <string>, "name": <string>, "admin":
+ <string>, "email": <string>, "password":
+ <string>}
+ Curl example
+ curl -X POST {{ request.url_root }}usermanager/api/v1/users -d
+ '{"admin_id": "{{ user.id }}", "wallet_name": <string>,
+ "user_name": <string>, "email": <Optional string>,
+ "password": < Optional string>}' -H "X-Api-Key: {{
+ user.wallets[0].inkey }}" -H "Content-type: application/json"
+
+ POST
+ /usermanager/api/v1/wallets
+ Headers
+ {"X-Api-Key": <string>, "Content-type":
+ "application/json"}
+
+ Body (application/json) - "admin_id" is a YOUR user ID
+
+ {"user_id": <string>, "wallet_name": <string>,
+ "admin_id": <string>}
+
+ Returns 201 CREATED (application/json)
+
+ {"id": <string>, "admin": <string>, "name":
+ <string>, "user": <string>, "adminkey": <string>,
+ "inkey": <string>}
+ Curl example
+ curl -X POST {{ request.url_root }}usermanager/api/v1/wallets -d
+ '{"user_id": <string>, "wallet_name": <string>,
+ "admin_id": "{{ user.id }}"}' -H "X-Api-Key: {{ user.wallets[0].inkey
+ }}" -H "Content-type: application/json"
+
+ DELETE
+ /usermanager/api/v1/users/<user_id>
+ Headers
+ {"X-Api-Key": <string>}
+ Curl example
+ curl -X DELETE {{ request.url_root
+ }}usermanager/api/v1/users/<user_id> -H "X-Api-Key: {{
+ user.wallets[0].inkey }}"
+
+ DELETE
+ /usermanager/api/v1/wallets/<wallet_id>
+ Headers
+ {"X-Api-Key": <string>}
+ Curl example
+ curl -X DELETE {{ request.url_root
+ }}usermanager/api/v1/wallets/<wallet_id> -H "X-Api-Key: {{
+ user.wallets[0].inkey }}"
+
+ POST
+ /usermanager/api/v1/extensions
+ Headers
+ {"X-Api-Key": <string>}
+ Curl example
+ curl -X POST {{ request.url_root }}usermanager/api/v1/extensions -d
+ '{"userid": <string>, "extension": <string>, "active":
+ <integer>}' -H "X-Api-Key: {{ user.wallets[0].inkey }}" -H
+ "Content-type: application/json"
+
+