diff --git a/.nuget/nuget.exe b/.nuget/nuget.exe
new file mode 100644
index 0000000..ed048fe
Binary files /dev/null and b/.nuget/nuget.exe differ
diff --git a/PAYNLSDK/API/Alliance/AddBankAccount/AddBankAccountResult.cs b/PAYNLSDK/API/Alliance/AddBankAccount/AddBankAccountResult.cs
new file mode 100644
index 0000000..6a83a4e
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/AddBankAccount/AddBankAccountResult.cs
@@ -0,0 +1,16 @@
+using Newtonsoft.Json;
+
+namespace PAYNLSDK.API.Alliance.AddBankAccount
+{
+ ///
+ /// Result class for AddBankAccount call
+ ///
+ public class AddBankAccountResult : ResponseBase
+ {
+ ///
+ /// The URL to redirect the user to for iDEAL verification
+ ///
+ [JsonProperty("issuerUrl")]
+ public string IssuerUrl { get; set; }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/AddBankAccount/Request.cs b/PAYNLSDK/API/Alliance/AddBankAccount/Request.cs
new file mode 100644
index 0000000..db45591
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/AddBankAccount/Request.cs
@@ -0,0 +1,75 @@
+using System.Collections.Specialized;
+using PAYNLSDK.Exceptions;
+using PAYNLSDK.Utilities;
+
+namespace PAYNLSDK.API.Alliance.AddBankAccount
+{
+ ///
+ /// Request to add a bank account for a merchant with iDEAL verification
+ ///
+ public class Request : RequestBase
+ {
+ ///
+ protected override int Version => 7;
+ ///
+ protected override string Controller => "Alliance";
+ ///
+ protected override string Method => "addBankaccount";
+
+ ///
+ /// The merchant ID
+ ///
+ public string MerchantId { get; set; }
+
+ ///
+ /// The URL to redirect the user to after the iDEAL verification is completed
+ ///
+ public string ReturnUrl { get; set; }
+
+ ///
+ /// Optional: the bank ID, if omitted, the user will be asked for the bank
+ ///
+ public string BankId { get; set; }
+
+ ///
+ /// Optional: the ID of the payment profile (standard iDEAL)
+ ///
+ public string PaymentOptionId { get; set; }
+
+ ///
+ public override NameValueCollection GetParameters()
+ {
+ if (ParameterValidator.IsEmpty(MerchantId))
+ {
+ throw new PayNlException("MerchantId is required");
+ }
+ if (ParameterValidator.IsEmpty(ReturnUrl))
+ {
+ throw new PayNlException("ReturnUrl is required");
+ }
+
+ var retval = new NameValueCollection
+ {
+ { "merchantId", MerchantId },
+ { "returnUrl", ReturnUrl }
+ };
+
+ if (!string.IsNullOrEmpty(BankId))
+ {
+ retval.Add("bankId", BankId);
+ }
+ if (!string.IsNullOrEmpty(PaymentOptionId))
+ {
+ retval.Add("paymentOptionId", PaymentOptionId);
+ }
+
+ return retval;
+ }
+
+ ///
+ protected override void PrepareAndSetResponse()
+ {
+ // do nothing
+ }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/AddClearing/AddClearingResult.cs b/PAYNLSDK/API/Alliance/AddClearing/AddClearingResult.cs
new file mode 100644
index 0000000..a4e0e9e
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/AddClearing/AddClearingResult.cs
@@ -0,0 +1,13 @@
+namespace PAYNLSDK.API.Alliance.AddClearing
+{
+ ///
+ /// Result class for AddClearing call
+ ///
+ public class AddClearingResult : ResponseBase
+ {
+ ///
+ /// Returns true if clearing was successfully added
+ ///
+ public bool Success => Request?.Result == true;
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/AddClearing/Request.cs b/PAYNLSDK/API/Alliance/AddClearing/Request.cs
new file mode 100644
index 0000000..bf041e7
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/AddClearing/Request.cs
@@ -0,0 +1,65 @@
+using System.Collections.Specialized;
+using PAYNLSDK.Exceptions;
+using PAYNLSDK.Utilities;
+
+namespace PAYNLSDK.API.Alliance.AddClearing
+{
+ ///
+ /// Request to add clearing for a merchant
+ ///
+ public class Request : RequestBase
+ {
+ ///
+ protected override int Version => 4;
+ ///
+ protected override string Controller => "Merchant";
+ ///
+ protected override string Method => "addClearing";
+
+ ///
+ /// The amount in cents
+ ///
+ public int Amount { get; set; }
+
+ ///
+ /// The merchant ID (optional)
+ ///
+ public string MerchantId { get; set; }
+
+ ///
+ /// The content category ID (optional)
+ ///
+ public string ContentCategoryId { get; set; }
+
+ ///
+ public override NameValueCollection GetParameters()
+ {
+ if (Amount <= 0)
+ {
+ throw new PayNlException("Amount is required and must be greater than 0");
+ }
+
+ var retval = new NameValueCollection
+ {
+ { "amount", Amount.ToString() }
+ };
+
+ if (!string.IsNullOrEmpty(MerchantId))
+ {
+ retval.Add("merchantId", MerchantId);
+ }
+ if (!string.IsNullOrEmpty(ContentCategoryId))
+ {
+ retval.Add("contentCategoryId", ContentCategoryId);
+ }
+
+ return retval;
+ }
+
+ ///
+ protected override void PrepareAndSetResponse()
+ {
+ // do nothing
+ }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/AddDocument/AddDocumentResult.cs b/PAYNLSDK/API/Alliance/AddDocument/AddDocumentResult.cs
new file mode 100644
index 0000000..182d55c
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/AddDocument/AddDocumentResult.cs
@@ -0,0 +1,22 @@
+using Newtonsoft.Json;
+
+namespace PAYNLSDK.API.Alliance.AddDocument
+{
+ ///
+ /// Result class for AddDocument call
+ ///
+ public class AddDocumentResult : ResponseBase
+ {
+ ///
+ /// Returns true if document was successfully uploaded
+ ///
+ [JsonProperty("result")]
+ public bool Result { get; set; }
+
+ ///
+ /// Document ID if successful
+ ///
+ [JsonProperty("documentId")]
+ public string DocumentId { get; set; }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/AddDocument/Request.cs b/PAYNLSDK/API/Alliance/AddDocument/Request.cs
new file mode 100644
index 0000000..cda12a2
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/AddDocument/Request.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using PAYNLSDK.Exceptions;
+using PAYNLSDK.Utilities;
+
+namespace PAYNLSDK.API.Alliance.AddDocument
+{
+ ///
+ /// Request to upload a document
+ ///
+ public class Request : RequestBase
+ {
+ ///
+ protected override int Version => 1;
+ ///
+ protected override string Controller => "Document";
+ ///
+ protected override string Method => "add";
+
+ ///
+ /// The document ID
+ ///
+ public string DocumentId { get; set; }
+
+ ///
+ /// The filename
+ ///
+ public string Filename { get; set; }
+
+ ///
+ /// Base64 encoded document content(s)
+ ///
+ public List Content { get; set; } = new List();
+
+ ///
+ /// Add base64 encoded content
+ ///
+ /// Base64 encoded document content
+ public void AddContent(string base64Content)
+ {
+ Content.Add(base64Content);
+ }
+
+ ///
+ public override NameValueCollection GetParameters()
+ {
+ if (ParameterValidator.IsEmpty(DocumentId))
+ {
+ throw new PayNlException("DocumentId is required");
+ }
+ if (ParameterValidator.IsEmpty(Filename))
+ {
+ throw new PayNlException("Filename is required");
+ }
+ if (Content == null || Content.Count == 0)
+ {
+ throw new PayNlException("Content is required");
+ }
+
+ var retval = new NameValueCollection
+ {
+ { "documentId", DocumentId },
+ { "filename", Filename }
+ };
+
+ if (Content.Count == 1)
+ {
+ retval.Add("documentFile", Content[0]);
+ }
+ else
+ {
+ for (int i = 0; i < Content.Count; i++)
+ {
+ retval.Add($"documentFile[{i}]", Content[i]);
+ }
+ }
+
+ return retval;
+ }
+
+ ///
+ protected override void PrepareAndSetResponse()
+ {
+ // do nothing
+ }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/DisablePaymentOption/DisablePaymentOptionResult.cs b/PAYNLSDK/API/Alliance/DisablePaymentOption/DisablePaymentOptionResult.cs
new file mode 100644
index 0000000..874b09e
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/DisablePaymentOption/DisablePaymentOptionResult.cs
@@ -0,0 +1,13 @@
+namespace PAYNLSDK.API.Alliance.DisablePaymentOption
+{
+ ///
+ /// Result class for DisablePaymentOption call
+ ///
+ public class DisablePaymentOptionResult : ResponseBase
+ {
+ ///
+ /// Returns true if the payment option was successfully disabled
+ ///
+ public bool Success => Request?.Result == true;
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/DisablePaymentOption/Request.cs b/PAYNLSDK/API/Alliance/DisablePaymentOption/Request.cs
new file mode 100644
index 0000000..3335fe5
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/DisablePaymentOption/Request.cs
@@ -0,0 +1,56 @@
+using System.Collections.Specialized;
+using PAYNLSDK.Exceptions;
+using PAYNLSDK.Utilities;
+
+namespace PAYNLSDK.API.Alliance.DisablePaymentOption
+{
+ ///
+ /// Request to disable a payment option for a service
+ ///
+ public class Request : RequestBase
+ {
+ ///
+ protected override int Version => 4;
+ ///
+ protected override string Controller => "Service";
+ ///
+ protected override string Method => "disablePaymentOption";
+
+ ///
+ /// The service ID
+ ///
+ public string ServiceId { get; set; }
+
+ ///
+ /// The payment profile ID (payment method ID)
+ ///
+ public string PaymentProfileId { get; set; }
+
+ ///
+ public override NameValueCollection GetParameters()
+ {
+ if (ParameterValidator.IsEmpty(ServiceId))
+ {
+ throw new PayNlException("ServiceId is required");
+ }
+ if (ParameterValidator.IsEmpty(PaymentProfileId))
+ {
+ throw new PayNlException("PaymentProfileId is required");
+ }
+
+ var retval = new NameValueCollection
+ {
+ { "serviceId", ServiceId },
+ { "paymentProfileId", PaymentProfileId }
+ };
+
+ return retval;
+ }
+
+ ///
+ protected override void PrepareAndSetResponse()
+ {
+ // do nothing
+ }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/EnablePaymentOption/EnablePaymentOptionResult.cs b/PAYNLSDK/API/Alliance/EnablePaymentOption/EnablePaymentOptionResult.cs
new file mode 100644
index 0000000..8d35d2a
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/EnablePaymentOption/EnablePaymentOptionResult.cs
@@ -0,0 +1,13 @@
+namespace PAYNLSDK.API.Alliance.EnablePaymentOption
+{
+ ///
+ /// Result class for EnablePaymentOption call
+ ///
+ public class EnablePaymentOptionResult : ResponseBase
+ {
+ ///
+ /// Returns true if the payment option was successfully enabled
+ ///
+ public bool Success => Request?.Result == true;
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/EnablePaymentOption/Request.cs b/PAYNLSDK/API/Alliance/EnablePaymentOption/Request.cs
new file mode 100644
index 0000000..81f473b
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/EnablePaymentOption/Request.cs
@@ -0,0 +1,70 @@
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using PAYNLSDK.Exceptions;
+using PAYNLSDK.Utilities;
+
+namespace PAYNLSDK.API.Alliance.EnablePaymentOption
+{
+ ///
+ /// Request to enable a payment option for a service
+ ///
+ public class Request : RequestBase
+ {
+ ///
+ protected override int Version => 4;
+ ///
+ protected override string Controller => "Service";
+ ///
+ protected override string Method => "enablePaymentOption";
+
+ ///
+ /// The service ID
+ ///
+ public string ServiceId { get; set; }
+
+ ///
+ /// The payment profile ID (payment method ID)
+ ///
+ public string PaymentProfileId { get; set; }
+
+ ///
+ /// Optional: settings for the payment option
+ ///
+ public Dictionary Settings { get; set; }
+
+ ///
+ public override NameValueCollection GetParameters()
+ {
+ if (ParameterValidator.IsEmpty(ServiceId))
+ {
+ throw new PayNlException("ServiceId is required");
+ }
+ if (ParameterValidator.IsEmpty(PaymentProfileId))
+ {
+ throw new PayNlException("PaymentProfileId is required");
+ }
+
+ var retval = new NameValueCollection
+ {
+ { "serviceId", ServiceId },
+ { "paymentProfileId", PaymentProfileId }
+ };
+
+ if (Settings != null && Settings.Count > 0)
+ {
+ foreach (var setting in Settings)
+ {
+ retval.Add($"settings[{setting.Key}]", setting.Value);
+ }
+ }
+
+ return retval;
+ }
+
+ ///
+ protected override void PrepareAndSetResponse()
+ {
+ // do nothing
+ }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/GetAvailablePaymentOptions/GetAvailablePaymentOptionsResult.cs b/PAYNLSDK/API/Alliance/GetAvailablePaymentOptions/GetAvailablePaymentOptionsResult.cs
new file mode 100644
index 0000000..06ba20c
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/GetAvailablePaymentOptions/GetAvailablePaymentOptionsResult.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace PAYNLSDK.API.Alliance.GetAvailablePaymentOptions
+{
+ ///
+ /// Result class for GetAvailablePaymentOptions call
+ ///
+ public class GetAvailablePaymentOptionsResult : ResponseBase
+ {
+ ///
+ /// List of available payment options
+ ///
+ [JsonProperty("paymentOptions")]
+ public List PaymentOptions { get; set; } = new List();
+ }
+
+ ///
+ /// Payment option information
+ ///
+ public class PaymentOption
+ {
+ ///
+ /// Payment option ID
+ ///
+ [JsonProperty("id")]
+ public string Id { get; set; }
+
+ ///
+ /// Payment option name
+ ///
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ ///
+ /// Whether the payment option is enabled
+ ///
+ [JsonProperty("enabled")]
+ public bool Enabled { get; set; }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/GetAvailablePaymentOptions/Request.cs b/PAYNLSDK/API/Alliance/GetAvailablePaymentOptions/Request.cs
new file mode 100644
index 0000000..aa0885c
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/GetAvailablePaymentOptions/Request.cs
@@ -0,0 +1,41 @@
+using System.Collections.Specialized;
+using PAYNLSDK.Exceptions;
+using PAYNLSDK.Utilities;
+
+namespace PAYNLSDK.API.Alliance.GetAvailablePaymentOptions
+{
+ ///
+ /// Request to get available payment options for a service
+ ///
+ public class Request : RequestBase
+ {
+ ///
+ protected override int Version => 4;
+ ///
+ protected override string Controller => "Service";
+ ///
+ protected override string Method => "getAvailablePaymentOptions";
+
+ ///
+ /// The service ID
+ ///
+ public string ServiceId { get; set; }
+
+ ///
+ public override NameValueCollection GetParameters()
+ {
+ if (ParameterValidator.IsEmpty(ServiceId))
+ {
+ throw new PayNlException("ServiceId is required");
+ }
+ var retval = new NameValueCollection { { "serviceId", ServiceId } };
+ return retval;
+ }
+
+ ///
+ protected override void PrepareAndSetResponse()
+ {
+ // do nothing
+ }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/GetCategories/GetCategoriesResult.cs b/PAYNLSDK/API/Alliance/GetCategories/GetCategoriesResult.cs
new file mode 100644
index 0000000..d8d0a0b
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/GetCategories/GetCategoriesResult.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace PAYNLSDK.API.Alliance.GetCategories
+{
+ ///
+ /// Result class for GetCategories call
+ ///
+ public class GetCategoriesResult : ResponseBase
+ {
+ ///
+ /// List of categories
+ ///
+ [JsonProperty("categories")]
+ public List Categories { get; set; } = new List();
+ }
+
+ ///
+ /// Category information
+ ///
+ public class Category
+ {
+ ///
+ /// Category ID
+ ///
+ [JsonProperty("id")]
+ public string Id { get; set; }
+
+ ///
+ /// Category name
+ ///
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ ///
+ /// Category description
+ ///
+ [JsonProperty("description")]
+ public string Description { get; set; }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/GetCategories/Request.cs b/PAYNLSDK/API/Alliance/GetCategories/Request.cs
new file mode 100644
index 0000000..3574ed9
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/GetCategories/Request.cs
@@ -0,0 +1,39 @@
+using System.Collections.Specialized;
+
+namespace PAYNLSDK.API.Alliance.GetCategories
+{
+ ///
+ /// Request to get website categories
+ ///
+ public class Request : RequestBase
+ {
+ ///
+ protected override int Version => 4;
+ ///
+ protected override string Controller => "Service";
+ ///
+ protected override string Method => "getCategories";
+
+ ///
+ /// Optional: filter by payment option ID
+ ///
+ public string PaymentOptionId { get; set; }
+
+ ///
+ public override NameValueCollection GetParameters()
+ {
+ var retval = new NameValueCollection();
+ if (!string.IsNullOrEmpty(PaymentOptionId))
+ {
+ retval.Add("paymentOptionId", PaymentOptionId);
+ }
+ return retval;
+ }
+
+ ///
+ protected override void PrepareAndSetResponse()
+ {
+ // do nothing
+ }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/GetMerchants/GetMerchantsResult.cs b/PAYNLSDK/API/Alliance/GetMerchants/GetMerchantsResult.cs
new file mode 100644
index 0000000..14788d4
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/GetMerchants/GetMerchantsResult.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace PAYNLSDK.API.Alliance.GetMerchants
+{
+ ///
+ /// Result class for GetMerchants call
+ ///
+ public class GetMerchantsResult : ResponseBase
+ {
+ ///
+ /// List of merchants
+ ///
+ [JsonProperty("merchants")]
+ public List Merchants { get; set; } = new List();
+ }
+
+ ///
+ /// Merchant information
+ ///
+ public class MerchantInfo
+ {
+ ///
+ /// Merchant ID
+ ///
+ [JsonProperty("merchantId")]
+ public string MerchantId { get; set; }
+
+ ///
+ /// Merchant name
+ ///
+ [JsonProperty("merchantName")]
+ public string MerchantName { get; set; }
+
+ ///
+ /// Merchant state
+ ///
+ [JsonProperty("state")]
+ public string State { get; set; }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/GetMerchants/Request.cs b/PAYNLSDK/API/Alliance/GetMerchants/Request.cs
new file mode 100644
index 0000000..6093ac1
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/GetMerchants/Request.cs
@@ -0,0 +1,39 @@
+using System.Collections.Specialized;
+
+namespace PAYNLSDK.API.Alliance.GetMerchants
+{
+ ///
+ /// Request to get a list of merchants
+ ///
+ public class Request : RequestBase
+ {
+ ///
+ protected override int Version => 7;
+ ///
+ protected override string Controller => "Alliance";
+ ///
+ protected override string Method => "getMerchants";
+
+ ///
+ /// Filter by state: new, accepted or deleted
+ ///
+ public string State { get; set; }
+
+ ///
+ public override NameValueCollection GetParameters()
+ {
+ var retval = new NameValueCollection();
+ if (!string.IsNullOrEmpty(State))
+ {
+ retval.Add("state", State);
+ }
+ return retval;
+ }
+
+ ///
+ protected override void PrepareAndSetResponse()
+ {
+ // do nothing
+ }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/MarkReady/MarkReadyResult.cs b/PAYNLSDK/API/Alliance/MarkReady/MarkReadyResult.cs
new file mode 100644
index 0000000..bf2cb5c
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/MarkReady/MarkReadyResult.cs
@@ -0,0 +1,13 @@
+namespace PAYNLSDK.API.Alliance.MarkReady
+{
+ ///
+ /// Result class for MarkReady call
+ ///
+ public class MarkReadyResult : ResponseBase
+ {
+ ///
+ /// Returns true if the merchant was successfully marked as ready
+ ///
+ public bool Success => Request?.Result == true;
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/MarkReady/Request.cs b/PAYNLSDK/API/Alliance/MarkReady/Request.cs
new file mode 100644
index 0000000..4cfc539
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/MarkReady/Request.cs
@@ -0,0 +1,41 @@
+using System.Collections.Specialized;
+using PAYNLSDK.Exceptions;
+using PAYNLSDK.Utilities;
+
+namespace PAYNLSDK.API.Alliance.MarkReady
+{
+ ///
+ /// Request to mark a merchant as ready
+ ///
+ public class Request : RequestBase
+ {
+ ///
+ protected override int Version => 4;
+ ///
+ protected override string Controller => "Merchant";
+ ///
+ protected override string Method => "markReady";
+
+ ///
+ /// The merchant ID to mark as ready
+ ///
+ public string MerchantId { get; set; }
+
+ ///
+ public override NameValueCollection GetParameters()
+ {
+ if (ParameterValidator.IsEmpty(MerchantId))
+ {
+ throw new PayNlException("MerchantId is required");
+ }
+ var retval = new NameValueCollection { { "merchantId", MerchantId } };
+ return retval;
+ }
+
+ ///
+ protected override void PrepareAndSetResponse()
+ {
+ // do nothing
+ }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/SetPackage/Request.cs b/PAYNLSDK/API/Alliance/SetPackage/Request.cs
new file mode 100644
index 0000000..fbe9bcb
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/SetPackage/Request.cs
@@ -0,0 +1,54 @@
+using System.Collections.Specialized;
+using PAYNLSDK.Exceptions;
+using PAYNLSDK.Utilities;
+
+namespace PAYNLSDK.API.Alliance.SetPackage
+{
+ ///
+ /// Request to set package for a merchant
+ ///
+ public class Request : RequestBase
+ {
+ ///
+ protected override int Version => 7;
+ ///
+ protected override string Controller => "Alliance";
+ ///
+ protected override string Method => "setPackage";
+
+ ///
+ /// The merchant ID
+ ///
+ public string MerchantId { get; set; }
+
+ ///
+ /// The package name (e.g. "Alliance" or "AlliancePlus")
+ ///
+ public string Package { get; set; }
+
+ ///
+ public override NameValueCollection GetParameters()
+ {
+ if (ParameterValidator.IsEmpty(MerchantId))
+ {
+ throw new PayNlException("MerchantId is required");
+ }
+ if (ParameterValidator.IsEmpty(Package))
+ {
+ throw new PayNlException("Package is required");
+ }
+ var retval = new NameValueCollection
+ {
+ { "merchantId", MerchantId },
+ { "package", Package }
+ };
+ return retval;
+ }
+
+ ///
+ protected override void PrepareAndSetResponse()
+ {
+ // do nothing
+ }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/SetPackage/SetPackageResult.cs b/PAYNLSDK/API/Alliance/SetPackage/SetPackageResult.cs
new file mode 100644
index 0000000..76a2617
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/SetPackage/SetPackageResult.cs
@@ -0,0 +1,13 @@
+namespace PAYNLSDK.API.Alliance.SetPackage
+{
+ ///
+ /// Result class for SetPackage call
+ ///
+ public class SetPackageResult : ResponseBase
+ {
+ ///
+ /// Returns true if the package was successfully set
+ ///
+ public bool Success => Request?.Result == true;
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/Suspend/Request.cs b/PAYNLSDK/API/Alliance/Suspend/Request.cs
new file mode 100644
index 0000000..18bb7dc
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/Suspend/Request.cs
@@ -0,0 +1,41 @@
+using System.Collections.Specialized;
+using PAYNLSDK.Exceptions;
+using PAYNLSDK.Utilities;
+
+namespace PAYNLSDK.API.Alliance.Suspend
+{
+ ///
+ /// Request to suspend a merchant
+ ///
+ public class Request : RequestBase
+ {
+ ///
+ protected override int Version => 7;
+ ///
+ protected override string Controller => "Alliance";
+ ///
+ protected override string Method => "suspend";
+
+ ///
+ /// The merchant ID to suspend
+ ///
+ public string MerchantId { get; set; }
+
+ ///
+ public override NameValueCollection GetParameters()
+ {
+ if (ParameterValidator.IsEmpty(MerchantId))
+ {
+ throw new PayNlException("MerchantId is required");
+ }
+ var retval = new NameValueCollection { { "merchantId", MerchantId } };
+ return retval;
+ }
+
+ ///
+ protected override void PrepareAndSetResponse()
+ {
+ // do nothing
+ }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/Suspend/SuspendResult.cs b/PAYNLSDK/API/Alliance/Suspend/SuspendResult.cs
new file mode 100644
index 0000000..77fa2db
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/Suspend/SuspendResult.cs
@@ -0,0 +1,13 @@
+namespace PAYNLSDK.API.Alliance.Suspend
+{
+ ///
+ /// Result class for Suspend call
+ ///
+ public class SuspendResult : ResponseBase
+ {
+ ///
+ /// Returns true if the merchant was successfully suspended
+ ///
+ public bool Success => Request?.Result == true;
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/Unsuspend/Request.cs b/PAYNLSDK/API/Alliance/Unsuspend/Request.cs
new file mode 100644
index 0000000..aef8071
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/Unsuspend/Request.cs
@@ -0,0 +1,41 @@
+using System.Collections.Specialized;
+using PAYNLSDK.Exceptions;
+using PAYNLSDK.Utilities;
+
+namespace PAYNLSDK.API.Alliance.Unsuspend
+{
+ ///
+ /// Request to unsuspend a merchant
+ ///
+ public class Request : RequestBase
+ {
+ ///
+ protected override int Version => 7;
+ ///
+ protected override string Controller => "Alliance";
+ ///
+ protected override string Method => "unsuspend";
+
+ ///
+ /// The merchant ID to unsuspend
+ ///
+ public string MerchantId { get; set; }
+
+ ///
+ public override NameValueCollection GetParameters()
+ {
+ if (ParameterValidator.IsEmpty(MerchantId))
+ {
+ throw new PayNlException("MerchantId is required");
+ }
+ var retval = new NameValueCollection { { "merchantId", MerchantId } };
+ return retval;
+ }
+
+ ///
+ protected override void PrepareAndSetResponse()
+ {
+ // do nothing
+ }
+ }
+}
diff --git a/PAYNLSDK/API/Alliance/Unsuspend/UnsuspendResult.cs b/PAYNLSDK/API/Alliance/Unsuspend/UnsuspendResult.cs
new file mode 100644
index 0000000..d6fc91c
--- /dev/null
+++ b/PAYNLSDK/API/Alliance/Unsuspend/UnsuspendResult.cs
@@ -0,0 +1,13 @@
+namespace PAYNLSDK.API.Alliance.Unsuspend
+{
+ ///
+ /// Result class for Unsuspend call
+ ///
+ public class UnsuspendResult : ResponseBase
+ {
+ ///
+ /// Returns true if the merchant was successfully unsuspended
+ ///
+ public bool Success => Request?.Result == true;
+ }
+}
diff --git a/PAYNLSDK/Alliance.cs b/PAYNLSDK/Alliance.cs
index f986c74..f175db6 100644
--- a/PAYNLSDK/Alliance.cs
+++ b/PAYNLSDK/Alliance.cs
@@ -47,5 +47,89 @@ public API.Alliance.AddInvoice.AddInvoiceResult AddInvoice(API.Alliance.AddInvoi
var response = _webClient.PerformRequest(request);
return Newtonsoft.Json.JsonConvert.DeserializeObject(response);
}
+
+ ///
+ public API.Alliance.GetMerchants.GetMerchantsResult GetMerchants(API.Alliance.GetMerchants.Request request)
+ {
+ var response = _webClient.PerformRequest(request);
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(response);
+ }
+
+ ///
+ public API.Alliance.Suspend.SuspendResult Suspend(API.Alliance.Suspend.Request request)
+ {
+ var response = _webClient.PerformRequest(request);
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(response);
+ }
+
+ ///
+ public API.Alliance.Unsuspend.UnsuspendResult Unsuspend(API.Alliance.Unsuspend.Request request)
+ {
+ var response = _webClient.PerformRequest(request);
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(response);
+ }
+
+ ///
+ public API.Alliance.SetPackage.SetPackageResult SetPackage(API.Alliance.SetPackage.Request request)
+ {
+ var response = _webClient.PerformRequest(request);
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(response);
+ }
+
+ ///
+ public API.Alliance.MarkReady.MarkReadyResult MarkReady(API.Alliance.MarkReady.Request request)
+ {
+ var response = _webClient.PerformRequest(request);
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(response);
+ }
+
+ ///
+ public API.Alliance.AddClearing.AddClearingResult AddClearing(API.Alliance.AddClearing.Request request)
+ {
+ var response = _webClient.PerformRequest(request);
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(response);
+ }
+
+ ///
+ public API.Alliance.AddBankAccount.AddBankAccountResult AddBankAccount(API.Alliance.AddBankAccount.Request request)
+ {
+ var response = _webClient.PerformRequest(request);
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(response);
+ }
+
+ ///
+ public API.Alliance.GetCategories.GetCategoriesResult GetCategories(API.Alliance.GetCategories.Request request)
+ {
+ var response = _webClient.PerformRequest(request);
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(response);
+ }
+
+ ///
+ public API.Alliance.GetAvailablePaymentOptions.GetAvailablePaymentOptionsResult GetAvailablePaymentOptions(API.Alliance.GetAvailablePaymentOptions.Request request)
+ {
+ var response = _webClient.PerformRequest(request);
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(response);
+ }
+
+ ///
+ public API.Alliance.EnablePaymentOption.EnablePaymentOptionResult EnablePaymentOption(API.Alliance.EnablePaymentOption.Request request)
+ {
+ var response = _webClient.PerformRequest(request);
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(response);
+ }
+
+ ///
+ public API.Alliance.DisablePaymentOption.DisablePaymentOptionResult DisablePaymentOption(API.Alliance.DisablePaymentOption.Request request)
+ {
+ var response = _webClient.PerformRequest(request);
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(response);
+ }
+
+ ///
+ public API.Alliance.AddDocument.AddDocumentResult AddDocument(API.Alliance.AddDocument.Request request)
+ {
+ var response = _webClient.PerformRequest(request);
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(response);
+ }
}
}
diff --git a/PAYNLSDK/IAlliance.cs b/PAYNLSDK/IAlliance.cs
index a7131de..03ddabb 100644
--- a/PAYNLSDK/IAlliance.cs
+++ b/PAYNLSDK/IAlliance.cs
@@ -32,5 +32,89 @@ public interface IAlliance
/// The request.
/// API.Alliance.AddInvoice.AddInvoiceResult.
API.Alliance.AddInvoice.AddInvoiceResult AddInvoice(API.Alliance.AddInvoice.Request request);
+
+ ///
+ /// Get a list of merchants
+ ///
+ /// The request.
+ /// API.Alliance.GetMerchants.GetMerchantsResult.
+ API.Alliance.GetMerchants.GetMerchantsResult GetMerchants(API.Alliance.GetMerchants.Request request);
+
+ ///
+ /// Suspend a merchant
+ ///
+ /// The request.
+ /// API.Alliance.Suspend.SuspendResult.
+ API.Alliance.Suspend.SuspendResult Suspend(API.Alliance.Suspend.Request request);
+
+ ///
+ /// Unsuspend a merchant
+ ///
+ /// The request.
+ /// API.Alliance.Unsuspend.UnsuspendResult.
+ API.Alliance.Unsuspend.UnsuspendResult Unsuspend(API.Alliance.Unsuspend.Request request);
+
+ ///
+ /// Set package for a merchant
+ ///
+ /// The request.
+ /// API.Alliance.SetPackage.SetPackageResult.
+ API.Alliance.SetPackage.SetPackageResult SetPackage(API.Alliance.SetPackage.Request request);
+
+ ///
+ /// Mark a merchant as ready
+ ///
+ /// The request.
+ /// API.Alliance.MarkReady.MarkReadyResult.
+ API.Alliance.MarkReady.MarkReadyResult MarkReady(API.Alliance.MarkReady.Request request);
+
+ ///
+ /// Add clearing for a merchant
+ ///
+ /// The request.
+ /// API.Alliance.AddClearing.AddClearingResult.
+ API.Alliance.AddClearing.AddClearingResult AddClearing(API.Alliance.AddClearing.Request request);
+
+ ///
+ /// Add bank account for a merchant with iDEAL verification
+ ///
+ /// The request.
+ /// API.Alliance.AddBankAccount.AddBankAccountResult.
+ API.Alliance.AddBankAccount.AddBankAccountResult AddBankAccount(API.Alliance.AddBankAccount.Request request);
+
+ ///
+ /// Get website categories
+ ///
+ /// The request.
+ /// API.Alliance.GetCategories.GetCategoriesResult.
+ API.Alliance.GetCategories.GetCategoriesResult GetCategories(API.Alliance.GetCategories.Request request);
+
+ ///
+ /// Get available payment options for a service
+ ///
+ /// The request.
+ /// API.Alliance.GetAvailablePaymentOptions.GetAvailablePaymentOptionsResult.
+ API.Alliance.GetAvailablePaymentOptions.GetAvailablePaymentOptionsResult GetAvailablePaymentOptions(API.Alliance.GetAvailablePaymentOptions.Request request);
+
+ ///
+ /// Enable a payment option for a service
+ ///
+ /// The request.
+ /// API.Alliance.EnablePaymentOption.EnablePaymentOptionResult.
+ API.Alliance.EnablePaymentOption.EnablePaymentOptionResult EnablePaymentOption(API.Alliance.EnablePaymentOption.Request request);
+
+ ///
+ /// Disable a payment option for a service
+ ///
+ /// The request.
+ /// API.Alliance.DisablePaymentOption.DisablePaymentOptionResult.
+ API.Alliance.DisablePaymentOption.DisablePaymentOptionResult DisablePaymentOption(API.Alliance.DisablePaymentOption.Request request);
+
+ ///
+ /// Upload a document
+ ///
+ /// The request.
+ /// API.Alliance.AddDocument.AddDocumentResult.
+ API.Alliance.AddDocument.AddDocumentResult AddDocument(API.Alliance.AddDocument.Request request);
}
}
diff --git a/PayNLSdk.Tests/AllianceTests.cs b/PayNLSdk.Tests/AllianceTests.cs
index 18af285..1a0f2c9 100644
--- a/PayNLSdk.Tests/AllianceTests.cs
+++ b/PayNLSdk.Tests/AllianceTests.cs
@@ -123,6 +123,352 @@ public void AddInvoice_ShouldReturnReferenceId()
result.ToString().ShouldContain("INV-1");
}
+ [Fact]
+ public void GetMerchants_ShouldReturnListOfMerchants()
+ {
+ // Arrange
+ var rawResponse = """
+ {
+ "request": {
+ "result": true,
+ "errorId": null,
+ "errorMessage": null
+ },
+ "merchants": [
+ {
+ "merchantId": "M-1",
+ "merchantName": "Merchant One",
+ "state": "accepted"
+ },
+ {
+ "merchantId": "M-2",
+ "merchantName": "Merchant Two",
+ "state": "new"
+ }
+ ]
+ }
+ """;
+ var client = CreateClient(rawResponse);
+ var alliance = new Alliance(client);
+
+ // Act
+ var result = alliance.GetMerchants(new PAYNLSDK.API.Alliance.GetMerchants.Request());
+
+ // Assert
+ result.Merchants.Count.ShouldBe(2);
+ result.Merchants[0].MerchantId.ShouldBe("M-1");
+ result.Merchants[0].MerchantName.ShouldBe("Merchant One");
+ result.Merchants[0].State.ShouldBe("accepted");
+ }
+
+ [Fact]
+ public void Suspend_ShouldReturnSuccess()
+ {
+ // Arrange
+ var rawResponse = """
+ {
+ "request": {
+ "result": true,
+ "errorId": null,
+ "errorMessage": null
+ }
+ }
+ """;
+ var client = CreateClient(rawResponse);
+ var alliance = new Alliance(client);
+
+ // Act
+ var result = alliance.Suspend(new PAYNLSDK.API.Alliance.Suspend.Request { MerchantId = "M-4" });
+
+ // Assert
+ result.Success.ShouldBeTrue();
+ }
+
+ [Fact]
+ public void Unsuspend_ShouldReturnSuccess()
+ {
+ // Arrange
+ var rawResponse = """
+ {
+ "request": {
+ "result": true,
+ "errorId": null,
+ "errorMessage": null
+ }
+ }
+ """;
+ var client = CreateClient(rawResponse);
+ var alliance = new Alliance(client);
+
+ // Act
+ var result = alliance.Unsuspend(new PAYNLSDK.API.Alliance.Unsuspend.Request { MerchantId = "M-4" });
+
+ // Assert
+ result.Success.ShouldBeTrue();
+ }
+
+ [Fact]
+ public void SetPackage_ShouldReturnSuccess()
+ {
+ // Arrange
+ var rawResponse = """
+ {
+ "request": {
+ "result": true,
+ "errorId": null,
+ "errorMessage": null
+ }
+ }
+ """;
+ var client = CreateClient(rawResponse);
+ var alliance = new Alliance(client);
+
+ // Act
+ var result = alliance.SetPackage(new PAYNLSDK.API.Alliance.SetPackage.Request
+ {
+ MerchantId = "M-4",
+ Package = "AlliancePlus"
+ });
+
+ // Assert
+ result.Success.ShouldBeTrue();
+ }
+
+ [Fact]
+ public void MarkReady_ShouldReturnSuccess()
+ {
+ // Arrange
+ var rawResponse = """
+ {
+ "request": {
+ "result": true,
+ "errorId": null,
+ "errorMessage": null
+ }
+ }
+ """;
+ var client = CreateClient(rawResponse);
+ var alliance = new Alliance(client);
+
+ // Act
+ var result = alliance.MarkReady(new PAYNLSDK.API.Alliance.MarkReady.Request { MerchantId = "M-4" });
+
+ // Assert
+ result.Success.ShouldBeTrue();
+ }
+
+ [Fact]
+ public void AddClearing_ShouldReturnSuccess()
+ {
+ // Arrange
+ var rawResponse = """
+ {
+ "request": {
+ "result": true,
+ "errorId": null,
+ "errorMessage": null
+ }
+ }
+ """;
+ var client = CreateClient(rawResponse);
+ var alliance = new Alliance(client);
+
+ // Act
+ var result = alliance.AddClearing(new PAYNLSDK.API.Alliance.AddClearing.Request
+ {
+ Amount = 1000,
+ MerchantId = "M-4"
+ });
+
+ // Assert
+ result.Success.ShouldBeTrue();
+ }
+
+ [Fact]
+ public void AddBankAccount_ShouldReturnIssuerUrl()
+ {
+ // Arrange
+ var rawResponse = """
+ {
+ "request": {
+ "result": true,
+ "errorId": null,
+ "errorMessage": null
+ },
+ "issuerUrl": "https://example.com/ideal"
+ }
+ """;
+ var client = CreateClient(rawResponse);
+ var alliance = new Alliance(client);
+
+ // Act
+ var result = alliance.AddBankAccount(new PAYNLSDK.API.Alliance.AddBankAccount.Request
+ {
+ MerchantId = "M-4",
+ ReturnUrl = "https://example.com/return"
+ });
+
+ // Assert
+ result.IssuerUrl.ShouldBe("https://example.com/ideal");
+ }
+
+ [Fact]
+ public void GetCategories_ShouldReturnListOfCategories()
+ {
+ // Arrange
+ var rawResponse = """
+ {
+ "request": {
+ "result": true,
+ "errorId": null,
+ "errorMessage": null
+ },
+ "categories": [
+ {
+ "id": "1",
+ "name": "Category 1",
+ "description": "Description 1"
+ },
+ {
+ "id": "2",
+ "name": "Category 2",
+ "description": "Description 2"
+ }
+ ]
+ }
+ """;
+ var client = CreateClient(rawResponse);
+ var alliance = new Alliance(client);
+
+ // Act
+ var result = alliance.GetCategories(new PAYNLSDK.API.Alliance.GetCategories.Request());
+
+ // Assert
+ result.Categories.Count.ShouldBe(2);
+ result.Categories[0].Id.ShouldBe("1");
+ result.Categories[0].Name.ShouldBe("Category 1");
+ }
+
+ [Fact]
+ public void GetAvailablePaymentOptions_ShouldReturnListOfOptions()
+ {
+ // Arrange
+ var rawResponse = """
+ {
+ "request": {
+ "result": true,
+ "errorId": null,
+ "errorMessage": null
+ },
+ "paymentOptions": [
+ {
+ "id": "10",
+ "name": "iDEAL",
+ "enabled": true
+ },
+ {
+ "id": "436",
+ "name": "Bancontact",
+ "enabled": false
+ }
+ ]
+ }
+ """;
+ var client = CreateClient(rawResponse);
+ var alliance = new Alliance(client);
+
+ // Act
+ var result = alliance.GetAvailablePaymentOptions(
+ new PAYNLSDK.API.Alliance.GetAvailablePaymentOptions.Request { ServiceId = "SL-1000-2000" });
+
+ // Assert
+ result.PaymentOptions.Count.ShouldBe(2);
+ result.PaymentOptions[0].Id.ShouldBe("10");
+ result.PaymentOptions[0].Name.ShouldBe("iDEAL");
+ result.PaymentOptions[0].Enabled.ShouldBeTrue();
+ }
+
+ [Fact]
+ public void EnablePaymentOption_ShouldReturnSuccess()
+ {
+ // Arrange
+ var rawResponse = """
+ {
+ "request": {
+ "result": true,
+ "errorId": null,
+ "errorMessage": null
+ }
+ }
+ """;
+ var client = CreateClient(rawResponse);
+ var alliance = new Alliance(client);
+
+ // Act
+ var result = alliance.EnablePaymentOption(new PAYNLSDK.API.Alliance.EnablePaymentOption.Request
+ {
+ ServiceId = "SL-1000-2000",
+ PaymentProfileId = "10"
+ });
+
+ // Assert
+ result.Success.ShouldBeTrue();
+ }
+
+ [Fact]
+ public void DisablePaymentOption_ShouldReturnSuccess()
+ {
+ // Arrange
+ var rawResponse = """
+ {
+ "request": {
+ "result": true,
+ "errorId": null,
+ "errorMessage": null
+ }
+ }
+ """;
+ var client = CreateClient(rawResponse);
+ var alliance = new Alliance(client);
+
+ // Act
+ var result = alliance.DisablePaymentOption(new PAYNLSDK.API.Alliance.DisablePaymentOption.Request
+ {
+ ServiceId = "SL-1000-2000",
+ PaymentProfileId = "10"
+ });
+
+ // Assert
+ result.Success.ShouldBeTrue();
+ }
+
+ [Fact]
+ public void AddDocument_ShouldReturnSuccess()
+ {
+ // Arrange
+ var rawResponse = """
+ {
+ "result": true,
+ "documentId": "D-1234-5678"
+ }
+ """;
+ var client = CreateClient(rawResponse);
+ var alliance = new Alliance(client);
+ var request = new PAYNLSDK.API.Alliance.AddDocument.Request
+ {
+ DocumentId = "D-1234-5678",
+ Filename = "test.pdf"
+ };
+ request.AddContent("base64encodedcontent");
+
+ // Act
+ var result = alliance.AddDocument(request);
+
+ // Assert
+ result.Result.ShouldBeTrue();
+ result.DocumentId.ShouldBe("D-1234-5678");
+ }
+
private static IClient CreateClient(string rawResponse)
{
var client = Substitute.For();