From b40095f6039dbce20ee92b2da8cd4530c7b8b486 Mon Sep 17 00:00:00 2001 From: Kukks Date: Tue, 12 Jan 2021 09:25:35 +0100 Subject: [PATCH] GreenField API: Configure Store Lightning Payment Method --- ...erClient.LightningNetworkPaymentMethods.cs | 63 ++++ .../LightningNetworkPaymentMethodData.cs | 31 ++ BTCPayServer.Tests/GreenfieldAPITests.cs | 64 +++- BTCPayServer.Tests/TestAccount.cs | 6 +- ...ightningNetworkPaymentMethodsController.cs | 249 +++++++++++++ .../StoreOnChainPaymentMethodsController.cs | 4 +- ...res-payment-methods.lightning-network.json | 334 ++++++++++++++++++ 7 files changed, 744 insertions(+), 7 deletions(-) create mode 100644 BTCPayServer.Client/BTCPayServerClient.LightningNetworkPaymentMethods.cs create mode 100644 BTCPayServer.Client/Models/LightningNetworkPaymentMethodData.cs create mode 100644 BTCPayServer/Controllers/GreenField/StoreLightningNetworkPaymentMethodsController.cs create mode 100644 BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.lightning-network.json diff --git a/BTCPayServer.Client/BTCPayServerClient.LightningNetworkPaymentMethods.cs b/BTCPayServer.Client/BTCPayServerClient.LightningNetworkPaymentMethods.cs new file mode 100644 index 000000000..5fc4cdc24 --- /dev/null +++ b/BTCPayServer.Client/BTCPayServerClient.LightningNetworkPaymentMethods.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using BTCPayServer.Client.Models; + +namespace BTCPayServer.Client +{ + public partial class BTCPayServerClient + { + public virtual async Task> + GetStoreLightningNetworkPaymentMethods(string storeId, + CancellationToken token = default) + { + var response = + await _httpClient.SendAsync( + CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork"), token); + return await HandleResponse>(response); + } + + public virtual async Task GetStoreLightningNetworkPaymentMethod( + string storeId, + string cryptoCode, CancellationToken token = default) + { + var response = + await _httpClient.SendAsync( + CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}"), token); + return await HandleResponse(response); + } + + public virtual async Task RemoveStoreLightningNetworkPaymentMethod(string storeId, + string cryptoCode, CancellationToken token = default) + { + var response = + await _httpClient.SendAsync( + CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}", + method: HttpMethod.Delete), token); + await HandleResponse(response); + } + + public virtual async Task UpdateStoreLightningNetworkPaymentMethod( + string storeId, + string cryptoCode, LightningNetworkPaymentMethodData paymentMethod, + CancellationToken token = default) + { + var response = await _httpClient.SendAsync( + CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}", + bodyPayload: paymentMethod, method: HttpMethod.Put), token); + return await HandleResponse(response); + } + + public virtual async Task + UpdateStoreLightningNetworkPaymentMethodToInternalNode(string storeId, + string cryptoCode, LightningNetworkPaymentMethodData paymentMethod, + CancellationToken token = default) + { + var response = await _httpClient.SendAsync( + CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}/internal", + method: HttpMethod.Put), token); + return await HandleResponse(response); + } + } +} diff --git a/BTCPayServer.Client/Models/LightningNetworkPaymentMethodData.cs b/BTCPayServer.Client/Models/LightningNetworkPaymentMethodData.cs new file mode 100644 index 000000000..3e12397cc --- /dev/null +++ b/BTCPayServer.Client/Models/LightningNetworkPaymentMethodData.cs @@ -0,0 +1,31 @@ +using NBitcoin; +using Newtonsoft.Json; + +namespace BTCPayServer.Client.Models +{ + public class LightningNetworkPaymentMethodData + { + /// + /// Whether the payment method is enabled + /// + public bool Enabled { get; set; } + + /// + /// Crypto code of the payment method + /// + public string CryptoCode { get; set; } + + public string ConnectionString { get; set; } + + public LightningNetworkPaymentMethodData() + { + } + + public LightningNetworkPaymentMethodData(string cryptoCode, string connectionString, bool enabled) + { + Enabled = enabled; + CryptoCode = cryptoCode; + ConnectionString = connectionString; + } + } +} diff --git a/BTCPayServer.Tests/GreenfieldAPITests.cs b/BTCPayServer.Tests/GreenfieldAPITests.cs index dbd135baf..00f41dad7 100644 --- a/BTCPayServer.Tests/GreenfieldAPITests.cs +++ b/BTCPayServer.Tests/GreenfieldAPITests.cs @@ -1266,10 +1266,70 @@ namespace BTCPayServer.Tests await client.GetStoreOnChainPaymentMethod(store.Id, "BTC"); }); } - - + + + [Fact(Timeout = 60 * 2 * 1000)] + [Trait("Lightning", "Lightning")] + [Trait("Integration", "Integration")] + public async Task LightningNetworkPaymentMethodAPITests() + { + using var tester = ServerTester.Create(); + tester.ActivateLightning(); + await tester.StartAsync(); + await tester.EnsureChannelsSetup(); + var user = tester.NewAccount(); + await user.GrantAccessAsync(true); + var client = await user.CreateClient(Policies.CanModifyStoreSettings); + var viewOnlyClient = await user.CreateClient(Policies.CanViewStoreSettings); + tester.PayTester.GetService().DevelopmentOverride = false; + var store = await client.GetStore(user.StoreId); + Assert.Empty(await client.GetStoreLightningNetworkPaymentMethods(store.Id)); + await AssertHttpError(403, async () => + { + await viewOnlyClient.UpdateStoreLightningNetworkPaymentMethod(store.Id, "BTC", new LightningNetworkPaymentMethodData() { }); + }); + await AssertHttpError(404, async () => + { + await client.GetStoreLightningNetworkPaymentMethod(store.Id, "BTC"); + }); + await user.RegisterLightningNodeAsync("BTC", LightningConnectionType.CLightning, false); + + var method = await client.GetStoreLightningNetworkPaymentMethod(store.Id, "BTC"); + await AssertHttpError(403, async () => + { + await viewOnlyClient.RemoveStoreOnChainPaymentMethod(store.Id, "BTC"); + }); + await client.RemoveStoreOnChainPaymentMethod(store.Id, "BTC"); + await AssertHttpError(404, async () => + { + await client.GetStoreOnChainPaymentMethod(store.Id, "BTC"); + }); + + var settings = (await tester.PayTester.GetService().GetSettingAsync())?? new PoliciesSettings(); + settings.AllowLightningInternalNodeForAll = false; + await tester.PayTester.GetService().UpdateSetting(settings); + var nonAdminUser = tester.NewAccount(); + await nonAdminUser.GrantAccessAsync(false); + var nonAdminUserClient= await nonAdminUser.CreateClient(Policies.CanModifyStoreSettings); + + await AssertHttpError(404, async () => + { + await nonAdminUserClient.GetStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC"); + }); + await Assert.ThrowsAsync(async () => + { + await nonAdminUserClient.UpdateStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC", method); + }); + + settings = await tester.PayTester.GetService().GetSettingAsync(); + settings.AllowLightningInternalNodeForAll = true; + await tester.PayTester.GetService().UpdateSetting(settings); + + await nonAdminUserClient.UpdateStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC", method); + } + [Fact(Timeout = TestTimeout)] [Trait("Fast", "Fast")] public void NumericJsonConverterTests() diff --git a/BTCPayServer.Tests/TestAccount.cs b/BTCPayServer.Tests/TestAccount.cs index 5c1608eda..b418b4812 100644 --- a/BTCPayServer.Tests/TestAccount.cs +++ b/BTCPayServer.Tests/TestAccount.cs @@ -257,7 +257,7 @@ namespace BTCPayServer.Tests RegisterLightningNodeAsync(cryptoCode, connectionType, isMerchant).GetAwaiter().GetResult(); } - public async Task RegisterLightningNodeAsync(string cryptoCode, LightningConnectionType connectionType, bool isMerchant = true) + public async Task RegisterLightningNodeAsync(string cryptoCode, LightningConnectionType connectionType, bool isMerchant = true, string storeId = null) { var storeController = this.GetController(); @@ -288,8 +288,8 @@ namespace BTCPayServer.Tests else throw new NotSupportedException(connectionType.ToString()); - await storeController.AddLightningNode(StoreId, - new LightningNodeViewModel() { ConnectionString = connectionString, SkipPortTest = true }, "save", "BTC"); + await storeController.AddLightningNode(storeId ?? StoreId, + new LightningNodeViewModel() {ConnectionString = connectionString, SkipPortTest = true}, "save", "BTC"); if (storeController.ModelState.ErrorCount != 0) Assert.False(true, storeController.ModelState.FirstOrDefault().Value.Errors[0].ErrorMessage); } diff --git a/BTCPayServer/Controllers/GreenField/StoreLightningNetworkPaymentMethodsController.cs b/BTCPayServer/Controllers/GreenField/StoreLightningNetworkPaymentMethodsController.cs new file mode 100644 index 000000000..ab781e658 --- /dev/null +++ b/BTCPayServer/Controllers/GreenField/StoreLightningNetworkPaymentMethodsController.cs @@ -0,0 +1,249 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using BTCPayServer.Abstractions.Constants; +using BTCPayServer.Client; +using BTCPayServer.Client.Models; +using BTCPayServer.Configuration; +using BTCPayServer.Data; +using BTCPayServer.HostedServices; +using BTCPayServer.Lightning; +using BTCPayServer.Payments; +using BTCPayServer.Payments.Lightning; +using BTCPayServer.Services; +using BTCPayServer.Services.Stores; +using BTCPayServer.Services.Wallets; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using NBitcoin; +using StoreData = BTCPayServer.Data.StoreData; + +namespace BTCPayServer.Controllers.GreenField +{ + [ApiController] + [Authorize(AuthenticationSchemes = AuthenticationSchemes.Greenfield)] + public class StoreLightningNetworkPaymentMethodsController : ControllerBase + { + private StoreData Store => HttpContext.GetStoreData(); + private readonly StoreRepository _storeRepository; + private readonly BTCPayNetworkProvider _btcPayNetworkProvider; + private readonly IOptions _lightningNetworkOptions; + private readonly CssThemeManager _cssThemeManager; + private readonly BTCPayServerEnvironment _btcPayServerEnvironment; + + public StoreLightningNetworkPaymentMethodsController( + StoreRepository storeRepository, + BTCPayNetworkProvider btcPayNetworkProvider, + IOptions lightningNetworkOptions, + CssThemeManager cssThemeManager, + BTCPayServerEnvironment btcPayServerEnvironment) + { + _storeRepository = storeRepository; + _btcPayNetworkProvider = btcPayNetworkProvider; + _lightningNetworkOptions = lightningNetworkOptions; + _cssThemeManager = cssThemeManager; + _btcPayServerEnvironment = btcPayServerEnvironment; + } + + [Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] + [HttpGet("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork")] + public ActionResult> GetLightningPaymentMethods( + [FromQuery] bool enabledOnly = false) + { + var blob = Store.GetStoreBlob(); + var excludedPaymentMethods = blob.GetExcludedPaymentMethods(); + return Ok(Store.GetSupportedPaymentMethods(_btcPayNetworkProvider) + .Where((method) => method.PaymentId.PaymentType == PaymentTypes.LightningLike) + .OfType() + .Select(strategy => + new LightningNetworkPaymentMethodData(strategy.PaymentId.CryptoCode, + strategy.AccountDerivation.ToString(), !excludedPaymentMethods.Match(strategy.PaymentId))) + .Where((result) => !enabledOnly || result.Enabled) + .ToList() + ); + } + + [Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] + [HttpGet("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}")] + public ActionResult GetLightningNetworkPaymentMethod(string cryptoCode) + { + if (!GetNetwork(cryptoCode, out BTCPayNetwork _)) + { + return NotFound(); + } + + var method = GetExistingLightningLikePaymentMethod(cryptoCode); + if (method is null) + { + return NotFound(); + } + return Ok(method); + } + + [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] + [HttpDelete("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}")] + public async Task RemoveLightningNetworkPaymentMethod( + string cryptoCode, + int offset = 0, int amount = 10) + { + if (!GetNetwork(cryptoCode, out BTCPayNetwork _)) + { + return NotFound(); + } + + var id = new PaymentMethodId(cryptoCode, PaymentTypes.LightningLike); + var store = Store; + store.SetSupportedPaymentMethod(id, null); + await _storeRepository.UpdateStore(store); + return Ok(); + } + + [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] + [HttpPut("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}")] + public async Task UpdateLightningNetworkPaymentMethod(string cryptoCode, + [FromBody] LightningNetworkPaymentMethodData paymentMethodData) + { + var id = new PaymentMethodId(cryptoCode, PaymentTypes.LightningLike); + + if (!GetNetwork(cryptoCode, out var network)) + { + return NotFound(); + } + + var internalLightning = GetInternalLightningNode(network.CryptoCode); + + if (string.IsNullOrEmpty(paymentMethodData?.ConnectionString)) + { + ModelState.AddModelError(nameof(LightningNetworkPaymentMethodData.ConnectionString), + "Missing connectionString"); + } + + if (!ModelState.IsValid) + return this.CreateValidationError(ModelState); + + + PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.LightningLike); + Payments.Lightning.LightningSupportedPaymentMethod paymentMethod = null; + if (!string.IsNullOrEmpty(paymentMethodData.ConnectionString)) + { + if (!LightningConnectionString.TryParse(paymentMethodData.ConnectionString, false, + out var connectionString, out var error)) + { + ModelState.AddModelError(nameof(paymentMethodData.ConnectionString), $"Invalid URL ({error})"); + return this.CreateValidationError(ModelState); + } + + if (connectionString.ConnectionType == LightningConnectionType.LndGRPC) + { + ModelState.AddModelError(nameof(paymentMethodData.ConnectionString), + $"BTCPay does not support gRPC connections"); + return this.CreateValidationError(ModelState); + } + + bool isInternalNode = connectionString.IsInternalNode(internalLightning); + + if (connectionString.BaseUri.Scheme == "http") + { + if (!isInternalNode && !connectionString.AllowInsecure) + { + ModelState.AddModelError(nameof(paymentMethodData.ConnectionString), "The url must be HTTPS"); + return this.CreateValidationError(ModelState); + } + } + + if (connectionString.MacaroonFilePath != null) + { + if (!CanUseInternalLightning()) + { + ModelState.AddModelError(nameof(paymentMethodData.ConnectionString), + "You are not authorized to use macaroonfilepath"); + return this.CreateValidationError(ModelState); + } + + if (!System.IO.File.Exists(connectionString.MacaroonFilePath)) + { + ModelState.AddModelError(nameof(paymentMethodData.ConnectionString), + "The macaroonfilepath file does not exist"); + return this.CreateValidationError(ModelState); + } + + if (!System.IO.Path.IsPathRooted(connectionString.MacaroonFilePath)) + { + ModelState.AddModelError(nameof(paymentMethodData.ConnectionString), + "The macaroonfilepath should be fully rooted"); + return this.CreateValidationError(ModelState); + } + } + + if (isInternalNode && !CanUseInternalLightning()) + { + ModelState.AddModelError(nameof(paymentMethodData.ConnectionString), "Unauthorized url"); + return this.CreateValidationError(ModelState); + } + + paymentMethod = new Payments.Lightning.LightningSupportedPaymentMethod() + { + CryptoCode = paymentMethodId.CryptoCode + }; + paymentMethod.SetLightningUrl(connectionString); + } + + var store = Store; + var storeBlob = store.GetStoreBlob(); + store.SetSupportedPaymentMethod(id, paymentMethod); + storeBlob.SetExcluded(id, !paymentMethodData.Enabled); + store.SetStoreBlob(storeBlob); + await _storeRepository.UpdateStore(store); + return Ok(GetExistingLightningLikePaymentMethod(cryptoCode, store)); + } + + + [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] + [HttpPut("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}/internal")] + public Task UpdateLightningNetworkPaymentMethodToInternalNode(string cryptoCode) + { + return UpdateLightningNetworkPaymentMethod(cryptoCode, + new LightningNetworkPaymentMethodData(cryptoCode, GetInternalLightningNode(cryptoCode).ToString(), true)); + } + + private LightningNetworkPaymentMethodData GetExistingLightningLikePaymentMethod(string cryptoCode, StoreData store = null) + { + store ??= Store; + var storeBlob = store.GetStoreBlob(); + var id = new PaymentMethodId(cryptoCode, PaymentTypes.LightningLike); + var paymentMethod = store + .GetSupportedPaymentMethods(_btcPayNetworkProvider) + .OfType() + .FirstOrDefault(method => method.PaymentId == id); + + var excluded = storeBlob.IsExcluded(id); + return paymentMethod == null + ? null + : new LightningNetworkPaymentMethodData(paymentMethod.PaymentId.CryptoCode, + paymentMethod.GetLightningUrl().ToString(), !excluded); + } + + private bool GetNetwork(string cryptoCode, out BTCPayNetwork network) + { + network = _btcPayNetworkProvider.GetNetwork(cryptoCode); + network = network?.SupportLightning is true ? network : null; + return network != null; + } + + private LightningConnectionString GetInternalLightningNode(string cryptoCode) + { + if (_lightningNetworkOptions.Value.InternalLightningByCryptoCode.TryGetValue(cryptoCode, out var connectionString)) + { + return CanUseInternalLightning() ? connectionString : null; + } + return null; + } + + private bool CanUseInternalLightning() + { + return (_btcPayServerEnvironment.IsDeveloping || User.IsInRole(Roles.ServerAdmin) || _cssThemeManager.AllowLightningInternalNodeForAll); + } + } +} diff --git a/BTCPayServer/Controllers/GreenField/StoreOnChainPaymentMethodsController.cs b/BTCPayServer/Controllers/GreenField/StoreOnChainPaymentMethodsController.cs index 0374970f3..f15fa57ea 100644 --- a/BTCPayServer/Controllers/GreenField/StoreOnChainPaymentMethodsController.cs +++ b/BTCPayServer/Controllers/GreenField/StoreOnChainPaymentMethodsController.cs @@ -165,12 +165,12 @@ namespace BTCPayServer.Controllers.GreenField }); } - return Ok(result); + return Ok(result); } [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] [HttpDelete("~/api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}")] - public async Task> RemoveOnChainPaymentMethod( + public async Task RemoveOnChainPaymentMethod( string cryptoCode, int offset = 0, int amount = 10) { diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.lightning-network.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.lightning-network.json new file mode 100644 index 000000000..f943d05c5 --- /dev/null +++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.lightning-network.json @@ -0,0 +1,334 @@ +{ + "paths": { + "/api/v1/stores/{storeId}/payment-methods/LightningNetwork": { + "get": { + "tags": [ + "Store Payment Methods (Lightning Network)" + ], + "summary": "Get store Lightning Network payment methods", + "description": "View information about the stores' configured Lightning Network payment methods", + "operationId": "StoreLightningNetworkPaymentMethods_GetLightningNetworkPaymentMethods", + "responses": { + "200": { + "description": "list of payment methods", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LightningNetworkPaymentMethodDataList" + } + } + } + } + }, + "security": [ + { + "API Key": [ + "btcpay.store.canviewstoresettings" + ], + "Basic": [] + } + ] + } + }, + "/api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}": { + "get": { + "tags": [ + "Store Payment Methods (Lightning Network)" + ], + "summary": "Get store Lightning Network payment method", + "parameters": [ + { + "name": "storeId", + "in": "path", + "required": true, + "description": "The store to fetch", + "schema": { + "type": "string" + } + }, + { + "name": "cryptoCode", + "in": "path", + "required": true, + "description": "The crypto code of the payment method to fetch", + "schema": { + "type": "string" + } + } + ], + "description": "View information about the specified payment method", + "operationId": "StoreLightningNetworkPaymentMethods_GetLightningNetworkPaymentMethod", + "responses": { + "200": { + "description": "specified payment method", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LightningNetworkPaymentMethodData" + } + } + } + }, + "403": { + "description": "If you are authenticated but forbidden to view the specified store" + }, + "404": { + "description": "The key is not found for this store/payment method" + } + }, + "security": [ + { + "API Key": [ + "btcpay.store.canviewstoresettings" + ], + "Basic": [] + } + ] + }, + "put": { + "tags": [ + "Store Payment Methods (Lightning Network)" + ], + "summary": "Update store Lightning Network payment method", + "parameters": [ + { + "name": "storeId", + "in": "path", + "required": true, + "description": "The store to fetch", + "schema": { + "type": "string" + } + }, + { + "name": "cryptoCode", + "in": "path", + "required": true, + "description": "The crypto code of the payment method to update", + "schema": { + "type": "string" + } + } + ], + "description": "Update the specified store's payment method", + "requestBody": { + "x-name": "request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LightningNetworkPaymentMethodData" + } + } + }, + "required": true, + "x-position": 1 + }, + "operationId": "StoreLightningNetworkPaymentMethods_UpdateLightningNetworkPaymentMethod", + "responses": { + "200": { + "description": "updated specified payment method", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LightningNetworkPaymentMethodData" + } + } + } + }, + "400": { + "description": "A list of errors that occurred when updating the store payment method", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } + }, + "403": { + "description": "If you are authenticated but forbidden to update the specified store" + }, + "404": { + "description": "The key is not found for this store" + } + }, + "security": [ + { + "API Key": [ + "btcpay.store.canmodifystoresettings" + ], + "Basic": [] + } + ] + }, + "delete": { + "tags": [ + "Store Payment Methods (Lightning Network)" + ], + "summary": "Remove store Lightning Network payment method", + "parameters": [ + { + "name": "storeId", + "in": "path", + "required": true, + "description": "The store to fetch", + "schema": { + "type": "string" + } + }, + { + "name": "cryptoCode", + "in": "path", + "required": true, + "description": "The crypto code of the payment method to update", + "schema": { + "type": "string" + } + } + ], + "description": "Removes the specified store payment method.", + "responses": { + "200": { + "description": "The payment method has been removed" + }, + "400": { + "description": "A list of errors that occurred when removing the payment method", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } + }, + "403": { + "description": "If you are authenticated but forbidden to remove the specified payment method" + }, + "404": { + "description": "The key is not found for this store/payment-method" + } + }, + "security": [ + { + "API Key": [ + "btcpay.store.canmodifystoresettings" + ], + "Basic": [] + } + ] + } + }, + "/api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}/internal": { + "put": { + "tags": [ + "Store Payment Methods (Lightning Network)" + ], + "summary": "Update store Lightning Network payment method to internal node", + "parameters": [ + { + "name": "storeId", + "in": "path", + "required": true, + "description": "The store to fetch", + "schema": { + "type": "string" + } + }, + { + "name": "cryptoCode", + "in": "path", + "required": true, + "description": "The crypto code of the payment method to update", + "schema": { + "type": "string" + } + } + ], + "description": "Update the specified store's payment method", + "requestBody": { + "x-name": "request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LightningNetworkPaymentMethodData" + } + } + }, + "required": true, + "x-position": 1 + }, + "operationId": "StoreLightningNetworkPaymentMethods_UpdateLightningNetworkPaymentMethodToInternalNode", + "responses": { + "200": { + "description": "updated specified payment method", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LightningNetworkPaymentMethodData" + } + } + } + }, + "400": { + "description": "A list of errors that occurred when updating the store payment method", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } + }, + "403": { + "description": "If you are authenticated but forbidden to update the specified store" + }, + "404": { + "description": "The key is not found for this store" + } + }, + "security": [ + { + "API Key": [ + "btcpay.store.canmodifystoresettings" + ], + "Basic": [] + } + ] + } + } + }, + "components": { + "schemas": { + "LightningNetworkPaymentMethodDataList": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LightningNetworkPaymentMethodData" + } + }, + "LightningNetworkPaymentMethodData": { + "type": "object", + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether the payment method is enabled" + }, + "cryptoCode": { + "type": "string", + "description": "Crypto code of the payment method" + }, + "connectionString": { + "type": "string", + "description": "The lightning connection string", + "example": "xpub..." + } + } + } + } + }, + "tags": [ + { + "name": "Store Payment Methods (Lightning Network)" + } + ] +}