SpareApi 0.0.1
dotnet add package SpareApi --version 0.0.1
NuGet\Install-Package SpareApi -Version 0.0.1
<PackageReference Include="SpareApi" Version="0.0.1" />
<PackageVersion Include="SpareApi" Version="0.0.1" />
<PackageReference Include="SpareApi" />
paket add SpareApi --version 0.0.1
#r "nuget: SpareApi, 0.0.1"
#:package SpareApi@0.0.1
#addin nuget:?package=SpareApi&version=0.0.1
#tool nuget:?package=SpareApi&version=0.0.1
SpareApi .NET SDK
The official .NET / C# SDK for the SpareApi Open Banking API.
Table of Contents
Installation
dotnet add package SpareApi
Requires .NET 6.0 or later. The package is available on NuGet.
Versioning
The SDK follows Semantic Versioning. Breaking changes are indicated by a major version bump. The changelog is available on the GitHub releases page.
All users are strongly recommended to use a recent version of the library, as older versions may not contain support for new endpoints and fields.
Getting Started
Configuration
using SpareApi;
// 1. Create a Configuration with your credentials
var config = new Configuration(new ConfigurationOptions
{
AppId = Environment.GetEnvironmentVariable("SPARE_APP_ID")!,
ApiKey = Environment.GetEnvironmentVariable("SPARE_API_KEY")!,
Tenant = Environment.GetEnvironmentVariable("SPARE_TENANT")!,
});
// 2. Pass it to the client — that's it
var client = new SpareApiClient(config);
// Token exchange happens automatically on the first request.
// X-Tenant header is injected on every request.
var providers = await client.Providers.ListAsync(
new ListProvidersRequest { CountryCode = "AE" }
);
foreach (var provider in providers.Data)
{
provider.Switch(
ksa => Console.WriteLine($"{ksa.Id} {ksa.EnglishName}"),
bahrain => Console.WriteLine($"{bahrain.Id} {bahrain.EnglishName}"),
uae => Console.WriteLine($"{uae.Id} {uae.Name}")
);
}
Required environment variables:
| Variable | Description |
|---|---|
SPARE_APP_ID |
App ID from your Spare dashboard |
SPARE_API_KEY |
API key from your Spare dashboard |
SPARE_TENANT |
Tenant identifier: UAE or KSA |
Configuration options
| Option | Type | Default | Description |
|---|---|---|---|
AppId |
string |
required | App ID from your Spare dashboard |
ApiKey |
string |
required | API key from your Spare dashboard |
Tenant |
string |
required | Tenant identifier: "UAE" or "KSA" |
Environment |
SpareEnvironment |
SpareEnvironment.Sandbox |
API environment |
BaseUrl |
string? |
derived from Environment | Override base URL (e.g., local dev server) |
RefreshThresholdMs |
int |
1_800_000 (30 min) |
Time before expiry to proactively refresh |
TokenExchangeTimeout |
TimeSpan |
10 seconds |
Timeout for token exchange/refresh requests |
Multi-environment support
// Sandbox (default)
var sandboxConfig = new Configuration(new ConfigurationOptions
{
AppId = "...", ApiKey = "...", Tenant = "UAE",
Environment = SpareEnvironment.Sandbox,
});
// Production
var productionConfig = new Configuration(new ConfigurationOptions
{
AppId = "...", ApiKey = "...", Tenant = "UAE",
Environment = SpareEnvironment.Production,
});
// Local development
var localConfig = new Configuration(new ConfigurationOptions
{
AppId = "...", ApiKey = "...", Tenant = "UAE",
BaseUrl = "http://localhost:4000", // overrides Environment
});
Error Handling
All non-2xx responses throw a SpareApiApiException. Inspect StatusCode and Body to handle
specific error types:
using SpareApi;
try
{
var consent = await client.PaymentConsents.GetAsync(
new GetPaymentConsentsRequest { ConsentId = "consent-id" }
);
}
catch (SpareApiApiException e)
{
Console.Error.WriteLine(e.StatusCode); // HTTP status — e.g. 404
Console.Error.WriteLine(e.Body); // raw response body
throw;
}
Examples
For more examples see the API reference documentation.
List providers
Retrieve the open-banking providers available in a given country:
var providers = await client.Providers.ListAsync(
new ListProvidersRequest { CountryCode = "AE" }
);
foreach (var provider in providers.Data)
{
provider.Switch(
ksa => Console.WriteLine($"{ksa.Id} {ksa.EnglishName}"),
bahrain => Console.WriteLine($"{bahrain.Id} {bahrain.EnglishName}"),
uae => Console.WriteLine($"{uae.Id} {uae.Name}")
);
}
Create a payment request
Payment requests require a request signature. Use client.Crypto.SignPayload to produce
the ES256 detached JWS and pass it as Signature:
var body = new Dictionary<string, object>
{
["type"] = "SingleInstantPayment",
["purpose"] = "ACM",
["creditorType"] = "MERCHANT",
["creditorReference"] = "INV-10042",
["creditorAccount"] = new Dictionary<string, object>
{
["identification"] = "AE070331234567890123456",
["name"] = "Acme Corp",
["schemeName"] = "IBAN",
},
["instructions"] = new Dictionary<string, object>
{
["amount"] = new Dictionary<string, object>
{
["amount"] = "250.00",
["currency"] = "AED",
},
},
};
var xSignature = client.Crypto.SignPayload(
Environment.GetEnvironmentVariable("SPARE_PRIVATE_KEY_PEM")!, body);
var paymentRequest = await client.PaymentRequests.CreateAsync(
new CreatePaymentRequestsRequest
{
Type = "SingleInstantPayment",
Purpose = "ACM",
CreditorType = "MERCHANT",
CreditorReference = "INV-10042",
MerchantReference = "INV-10042",
CreditorAccount = new CreatePaymentRequestsRequestCreditorAccount
{
Identification = "AE070331234567890123456",
Name = "Acme Corp",
SchemeName = "IBAN",
},
Instructions = new PaymentIPaymentInstructionsUae
{
Amount = new PaymentIAmountDtoUae { Amount = "250.00", Currency = "AED" },
},
Signature = xSignature,
}
);
Console.WriteLine($"Payment request: {paymentRequest.Data.Id}");
// Redirect the user to this URL to authorise the payment at their bank
Console.WriteLine($"Authorise at: {paymentRequest.Data.RedirectUrl}");
Check payment consent status
After the user authorises at the bank (via RedirectUrl), consent is created server-side.
Poll or sync status using PaymentConsents.ListAsync, PaymentConsents.GetAsync, or
PaymentConsents.SyncAsync:
// List all consents (paginated)
var consents = await client.PaymentConsents.ListAsync(
new ListPaymentConsentsRequest { Page = 1, PerPage = 10 }
);
foreach (var c in consents.Data)
{
Console.WriteLine($"{c.Id} {c.Status}");
}
// Get a specific consent by ID
var consent = await client.PaymentConsents.GetAsync(
new GetPaymentConsentsRequest { ConsentId = "consent-id" }
);
Console.WriteLine($"Consent status: {consent.Data.Status}");
// Force a sync from the bank to get the latest status
var synced = await client.PaymentConsents.SyncAsync(
new SyncPaymentConsentsRequest { PaymentRequestId = paymentRequest.Data.Id }
);
Console.WriteLine($"Synced status: {synced.Data.Status}");
Get a payment
var payment = await client.Payments.GetAsync(
new GetPaymentsRequest { PaymentId = paymentId }
);
Console.WriteLine($"Status: {payment.Data.Status}");
Register a bank account
var account = await client.BankAccounts.CreateAsync(
new CreateBankAccountsRequest
{
AccountDetails = new CreateBankAccountsRequestAccountDetails
{
IdentificationNumber = "AE070331234567890123456",
Scheme = "IBAN",
},
AccountHolderDetails = new CreateBankAccountsRequestAccountHolderDetails
{
Name = "Acme Corp",
},
Name = "Primary settlement account",
}
);
Console.WriteLine($"Account registered: {account.Data.Id}");
Schedule a mandate
Scheduling a mandate also requires a request signature:
var mandateBody = new Dictionary<string, object>
{
["mandateId"] = "3fa85f64-5717-4562-b3fc-2c963f66afa6",
["amount"] = 500,
["executionDate"] = "2025-06-01",
};
var xSignature = client.Crypto.SignPayload(
Environment.GetEnvironmentVariable("SPARE_PRIVATE_KEY_PEM")!, mandateBody);
var mandate = await client.Mandates.ScheduleAsync(
new ScheduleMandatesRequest
{
MandateId = "3fa85f64-5717-4562-b3fc-2c963f66afa6",
Amount = 500,
ExecutionDate = "2025-06-01",
Signature = xSignature,
}
);
Console.WriteLine($"Mandate scheduled: {mandate.Data.Id}");
Verify a beneficiary
Confirm that a beneficiary account (IBAN) matches the expected name before creating a payment, to reduce misdirected-payment risk. No request signature is required.
var verification = await client.Verifications.VerifyBeneficiaryAsync(
new VerifyBeneficiaryVerificationsRequest
{
Iban = "AE070331234567890123456",
BeneficiaryName = "Acme Corp",
}
);
Console.WriteLine($"Result: {verification.Data.Result}");
Console.WriteLine($"Matched name: {verification.Data.BeneficiaryName}");
List saved debtor accounts
Debtor (payer) accounts saved against one of your end-customers. The end-customer is
identified by the required CustomerId header (a merchant-supplied UUID).
var accounts = await client.SavedDebtorAccounts.ListAsync(
new ListSavedDebtorAccountsRequest
{
CustomerId = Environment.GetEnvironmentVariable("SPARE_CUSTOMER_ID")!,
Page = 1,
PerPage = 20,
}
);
foreach (var account in accounts.Data)
{
Console.WriteLine($"{account.Id} {account.MaskedIdentification}");
}
Request signing (x-signature)
Certain endpoints — PaymentRequests.CreateAsync and Mandates.ScheduleAsync — require a
detached JWS signature, passed via the Signature field. The SDK ships a CryptoHelper
accessible via client.Crypto.
Generate a key pair and register the public key in your Spare dashboard:
openssl ecparam -genkey -name prime256v1 -noout | openssl pkcs8 -topk8 -nocrypt -out private.pem
openssl ec -in private.pem -pubout -out public.pem # register public.pem in dashboard
Using CryptoHelper standalone:
using SpareApi;
var crypto = new CryptoHelper();
// Canonical JSON (sorted keys, nulls omitted)
var canonical = crypto.SerializePayload(body);
Console.WriteLine("Canonical: " + canonical);
// ES256 detached JWS — pass as Signature (x-signature header)
var privateKeyPem = Environment.GetEnvironmentVariable("SPARE_PRIVATE_KEY_PEM")!;
var xSignature = crypto.SignPayload(privateKeyPem, body);
Console.WriteLine("x-signature: " + xSignature); // eyJhbGciOiJFUzI1NiJ9...<sig>
Contributing
See CONTRIBUTING.md.
License
This SDK is distributed under the MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 is compatible. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.6.2
- OneOf (>= 3.0.271)
- OneOf.Extended (>= 3.0.271)
- Portable.System.DateTimeOnly (>= 9.0.1)
- System.Net.Http (>= 4.3.4)
- System.Text.Json (>= 9.0.9)
- System.Text.RegularExpressions (>= 4.3.1)
-
.NETStandard 2.0
- OneOf (>= 3.0.271)
- OneOf.Extended (>= 3.0.271)
- Portable.System.DateTimeOnly (>= 9.0.1)
- System.Net.Http (>= 4.3.4)
- System.Text.Json (>= 9.0.9)
- System.Text.RegularExpressions (>= 4.3.1)
-
net8.0
- OneOf (>= 3.0.271)
- OneOf.Extended (>= 3.0.271)
- System.Net.Http (>= 4.3.4)
- System.Text.RegularExpressions (>= 4.3.1)
-
net9.0
- OneOf (>= 3.0.271)
- OneOf.Extended (>= 3.0.271)
- System.Net.Http (>= 4.3.4)
- System.Text.RegularExpressions (>= 4.3.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.1 | 0 | 8/10/2026 |