BTCPay plugin to accept GNU Taler payments with multi-asset support (CHF, KUDOS).
This is experimental software. GNU Taler is in active development and upstream protocol/API behavior may change. This plugin can break between BTCPay or Taler upgrades and should be deployed with caution in production.
- Copy nginx vhost rules in
/var/lib/docker/volumes/generated_nginx_vhost/_data/<your-host> - Copy
docker-fragments/opt-add-taler-merchant.custom.ymlindocker-compose-generator/docker-fragments/opt-add-taler-merchant.custom.yml - Run
export BTCPAYGEN_ADDITIONAL_FRAGMENTS="$BTCPAYGEN_ADDITIONAL_FRAGMENTS;opt-add-taler-merchant.custom" - Run
export TALER_MERCHANT_BASE_URL=https://<your-host>/taler-merchant/ - Run
. ./btcpay-setup.sh -i - In
Server settings -> Taler: set publicMerchant public base URLtohttps://<your-host>/taler-merchant/ - Initialize instance, generate API token, then
Savethen restart BTCPay. - Fetch/enable assets and add a bank account
- Follow the wire and KYC instructions to enable the bank account
Use the following Payto URI format: payto://iban/CH00000000000000000000?receiver-name=My%20Company%SA
Warning: only CHF iban are currently supported by the Taler exchange.
In order to receive CHF from taler-ops.ch you will have to have your iban added and follow the instructions:
If the bank account status is kyc-wire-required you will need to send from the same bank account the smallest amount possible to the payto instructions. It might take 1 or 2 days to complete.
Once the bank account is on status kyc-required you will be requested to validate the Terms of Services of the Taler exchange.
- Plugin code:
BTCPayServer.Plugins.Taler/ - Standalone merchant docker:
docker-compose.taler.yml - Merchant image/context for BTCPay docker:
docker/taler-merchant/ - BTCPay docker fragment:
docker-fragments/opt-add-taler-merchant.custom.yml
Prereqs:
- .NET 8 SDK
- BTCPay source available at
submodules/btcpayserver
Build:
dotnet publish BTCPayServer.Plugins.Taler/BTCPayServer.Plugins.Taler.csproj -c Release -o /tmp/taler-plugin-publish --no-restore -m:1The output directory contains the plugin payload used to create a .btcpay package for upload.
Go to Server settings -> Taler and configure:
Merchant base URL: internal URL reachable by BTCPay container, typicallyhttp://taler-merchant:9966/Merchant public base URL: public URL used in checkout links, typicallyhttps://<your-host>/taler-merchant/Merchant instance ID: usuallydefaultInstance passwordMerchant API token
Then:
Initialize instanceGenerate API token(usesscope: allandduration: forever)Check bank accountsFetch assets- Save and restart BTCPay when asset set changes
Expose merchant public endpoints through BTCPay nginx at /taler-merchant/ over HTTPS.
Minimal vhost snippet:
location /taler-merchant/ {
proxy_pass http://taler-merchant:9966/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~ ^/taler-merchant/(private|webui|management|instances/[^/]+/private)/ {
return 403;
}add this in /var/lib/docker/volumes/generated_nginx_vhost/_data/<your-host>
- Merchant private API calls use
Authorization: Bearer secret-token:... - Token scope must allow required operations.
allis used for provisioning flows. - If you see
401on private endpoints, regenerate token and save it in BTCPay.
There is no runtime "list all endpoints" endpoint in taler-merchant.
For backend 20:0:8, these are the relevant endpoints this plugin/deployment uses:
- Public:
GET /configGET /instances/{instance}/orders/{order_id}?token={claim_token}
- Provisioning/management:
POST /management/instances
- Instance private (Bearer token):
POST /instances/{instance}/private/tokenGET /instances/{instance}/private/accountsPOST /instances/{instance}/private/accountsDELETE /instances/{instance}/private/accounts/{h_wire}GET /instances/{instance}/private/kycGET /instances/{instance}/private/ordersPOST /instances/{instance}/private/ordersGET /instances/{instance}/private/orders/{order_id}
Canonical upstream reference:
Run the following commands inside BTCPayServer, replace secret-token:yoursecret with the Merchant API token
- Read Merchant Backend config (public endpoint)
docker run --rm --network generated_default curlimages/curl:8.12.1 -sS http://taler-merchant:9966/config
- Read all accounts in Merchant Backend
docker run --rm --network generated_default curlimages/curl:8.12.1 -i -sS \
-H "Authorization: Bearer secret-token:yoursecret" \
"http://taler-merchant:9966/instances/default/private/accounts"
- check KYC status of all accounts
docker run --rm --network generated_default curlimages/curl:8.12.1 -sS \
-H "Authorization: Bearer secret-token:yoursecret" \
"http://taler-merchant:9966/instances/default/private/kyc"
- list all orders
docker run --rm --network generated_default curlimages/curl:8.12.1 -sS \
-H "Authorization: Bearer secret-token:yoursecret" \
"http://taler-merchant:9966/instances/default/private/orders"
- list all paid and wired orders
docker run --rm --network generated_default curlimages/curl:8.12.1 -sS \
-H "Authorization: Bearer secret-token:yoursecret" \
"http://taler-merchant:9966/instances/default/private/orders?paid=yes&wired=yes&delta=-50"
GPLv3. See LICENSE.