BlinkDebitApiClient 1.8.4
dotnet add package BlinkDebitApiClient --version 1.8.4
NuGet\Install-Package BlinkDebitApiClient -Version 1.8.4
<PackageReference Include="BlinkDebitApiClient" Version="1.8.4" />
<PackageVersion Include="BlinkDebitApiClient" Version="1.8.4" />
<PackageReference Include="BlinkDebitApiClient" />
paket add BlinkDebitApiClient --version 1.8.4
#r "nuget: BlinkDebitApiClient, 1.8.4"
#:package BlinkDebitApiClient@1.8.4
#addin nuget:?package=BlinkDebitApiClient&version=1.8.4
#tool nuget:?package=BlinkDebitApiClient&version=1.8.4

Blink-Debit-API-Client-DotNet
Table of Contents
- Introduction
- Contributing
- Building and Testing Locally
- Minimum Requirements
- Dependency
- Quick Start
- Configuration
- Client Creation
- Request ID, Correlation ID and Idempotency Key
- Full Examples
- Individual API Call Examples
Introduction
This SDK allows merchants with .NET 8- or .NET 10-based e-commerce sites to seamlessly integrate with Blink PayNow and Blink AutoPay in order to accept digital payments.
This SDK is written in C# 12. The language version is pinned in Directory.Build.props so that both target frameworks compile identically — see Minimum Requirements for the plan to move to C# 14.
Contributing
We welcome contributions from the community. Your pull request will be reviewed by our team.
This project is licensed under the MIT License.
Building and Testing Locally
Prerequisites
- .NET 10 SDK (check with
dotnet --version) — required to build, as the package targets bothnet8.0andnet10.0 - The .NET 8 runtime as well, to run the
net8.0test pass
Compile
From the repository root:
dotnet restore
dotnet build --configuration Release
Test
Most tests are integration tests that call the real sandbox API, so sandbox OAuth credentials must be set as environment variables first:
export BLINKPAY_CLIENT_ID="your-sandbox-client-id"
export BLINKPAY_CLIENT_SECRET="your-sandbox-client-secret"
Then run:
# Full suite
dotnet test
# With detailed output
dotnet test --logger "console;verbosity=detailed"
# A specific test class
dotnet test --filter "FullyQualifiedName~QuickPaymentsApiTests"
# Only the dependency injection extension tests (no credentials required)
dotnet test src/BlinkDebitApiClient.Extensions.DependencyInjection.Test
Some tests are marked Skip because they require manual user authorisation in a browser — these are expected to be skipped.
Minimum Requirements
- .NET 8 or .NET 10
The package multi-targets net8.0 and net10.0, so it can be consumed from either.
Planned migration to C# 14
.NET 8 reaches end of life on 10 November 2026. The net8.0 target will be dropped in the next major version after that date, at which point:
<TargetFrameworks>in each.csprojnarrows tonet10.0alone.<LangVersion>inDirectory.Build.propsis raised from12to14.- The dual-SDK
setup-dotnetsteps in.github/workflows/drop back to10.0.xonly.
Until then the language version stays pinned at C# 12, because that is the highest version the net8.0 target supports. This is deliberate: without the pin, the language version would default from the target framework (C# 12 for net8.0, C# 14 for net10.0) and a C# 14 feature would compile on one leg while breaking the other.
Adding the dependency
- If via your IDE, look for
BlinkDebitApiClientin the NuGet tool - If via .NET command line interface, run
dotnet add package BlinkDebitApiClient --version - If via
.csprojfile, add<PackageReference Include="BlinkDebitApiClient" Version="<LATEST_VERSION>"/>
Quick Start
var logger = LoggerFactory
.Create(builder => builder
.SetMinimumLevel(LogLevel.Information)
.AddConsole()
.AddDebug())
.CreateLogger<MyProgram>();
var blinkpayUrl = "https://sandbox.debit.blinkpay.co.nz";
var clientId = "";
var clientSecret = "";
var timeout = 10000;
var client = new BlinkDebitClient(logger, blinkpayUrl, clientId, clientSecret, timeout);
var gatewayFlow = new GatewayFlow("https://www.blinkpay.co.nz/sample-merchant-return-page");
var authFlowDetail = new AuthFlowDetail(gatewayFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr("particulars", "code", "reference");
var amount = new Amount("0.01", Amount.CurrencyEnum.NZD);
var request = new QuickPaymentRequest(authFlow, pcr, amount);
try {
var qpCreateResponse = await client.CreateQuickPaymentAsync(request);
logger.LogInformation("Redirect URL: {}", qpCreateResponse.RedirectUri); // Redirect the consumer to this URL
var qpId = qpCreateResponse.QuickPaymentId;
var qpResponse = await client.AwaitSuccessfulQuickPaymentAsync(qpId, 300); // Will throw an exception if the payment was not successful after 5min
} catch (BlinkServiceException e) {
logger.LogError("Encountered an error: " + e.Message);
}
Configuration
- Customise/supply the required properties in your
appsettings.jsonand/orProperties/launchSettings.json. This file should be available in your project folder. - The BlinkPay Sandbox debit URL is
https://sandbox.debit.blinkpay.co.nzand the production debit URL ishttps://debit.blinkpay.co.nz. - The client credentials will be provided to you by BlinkPay as part of your on-boarding process.
- Properties can be supplied using environment variables.
Warning Take care not to check in your client ID and secret to your source control.
Configuration precedence
Configuration will be detected and loaded according to the hierarchy -
- As provided directly to client constructor
- Environment variables e.g.
export BLINKPAY_CLIENT_SECRET=... Properties/launchSettings.jsonappsettings.json- Default values
Configuration examples
Environment variables
The following values are recommended to be supplied using environment variables.
export BLINKPAY_DEBIT_URL=<BLINKPAY_DEBIT_URL>
export BLINKPAY_CLIENT_ID=<BLINKPAY_CLIENT_ID>
export BLINKPAY_CLIENT_SECRET=<BLINKPAY_CLIENT_SECRET>
launchSettings file
If you want to use your launchSettings file locally, substitute the correct values to your Properties/launchSettings.json file. Do not commit this file into your repository.
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"Demo": {
"commandName": "Project",
"environmentVariables": {
"BLINKPAY_DEBIT_URL": "<BLINKPAY_DEBIT_URL>",
"BLINKPAY_CLIENT_ID": "<BLINKPAY_CLIENT_ID>",
"BLINKPAY_CLIENT_SECRET": "<BLINKPAY_CLIENT_SECRET>",
"BLINKPAY_TIMEOUT": "10000",
"BLINKPAY_RETRY_ENABLED": "true"
}
}
}
}
appsettings file
To use your appsettings file, you can pass environment variables from command line or CI/CD for the placeholders into your appsettings.json file.
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"BlinkPay": {
"DebitUrl": "{BLINKPAY_DEBIT_URL}",
"ClientId": "{BLINKPAY_CLIENT_ID}",
"ClientSecret": "{BLINKPAY_CLIENT_SECRET}",
"Timeout": 10000,
"RetryEnabled": true
}
}
Client creation
ASP.NET Core Integration (Recommended)
The recommended approach for ASP.NET Core applications is to use the BlinkDebitApiClient.Extensions.DependencyInjection NuGet package:
dotnet add package BlinkDebitApiClient.Extensions.DependencyInjection
Configuration-based registration (recommended)
Configure via appsettings.json and register in Program.cs:
appsettings.json:
{
"BlinkPay": {
"DebitUrl": "https://sandbox.debit.blinkpay.co.nz",
"ClientId": "your-client-id",
"ClientSecret": "your-client-secret",
"TimeoutSeconds": 10,
"RetryEnabled": true
}
}
Program.cs:
using BlinkDebitApiClient.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// Register BlinkDebitClient from configuration
builder.Services.AddBlinkDebitClient(builder.Configuration);
var app = builder.Build();
Programmatic registration
Alternatively, configure options directly in code:
using BlinkDebitApiClient.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddBlinkDebitClient(options =>
{
options.DebitUrl = "https://sandbox.debit.blinkpay.co.nz";
options.ClientId = builder.Configuration["BlinkPay:ClientId"];
options.ClientSecret = builder.Configuration["BlinkPay:ClientSecret"];
options.TimeoutSeconds = 15;
options.RetryEnabled = true;
});
var app = builder.Build();
Consuming the client
Inject IBlinkDebitClient into your controllers or services:
public class PaymentController : ControllerBase
{
private readonly IBlinkDebitClient _blinkClient;
private readonly ILogger<PaymentController> _logger;
public PaymentController(IBlinkDebitClient blinkClient, ILogger<PaymentController> logger)
{
_blinkClient = blinkClient;
_logger = logger;
}
[HttpPost("quick-payment")]
public async Task<IActionResult> CreateQuickPayment([FromBody] QuickPaymentDto dto)
{
try
{
var gatewayFlow = new GatewayFlow(dto.RedirectUri);
var authFlowDetail = new AuthFlowDetail(gatewayFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr(dto.Particulars, dto.Code, dto.Reference);
var amount = new Amount(dto.Amount, Amount.CurrencyEnum.NZD);
var request = new QuickPaymentRequest(authFlow, pcr, amount);
var response = await _blinkClient.CreateQuickPaymentAsync(request);
return Ok(new { redirectUri = response.RedirectUri, quickPaymentId = response.QuickPaymentId });
}
catch (BlinkServiceException ex)
{
_logger.LogError(ex, "Failed to create quick payment");
return StatusCode(500, new { error = ex.Message });
}
}
}
Benefits:
- ✅ Automatic singleton lifetime management (follows HTTP client best practices)
- ✅ Configuration validation on startup (fail fast)
- ✅ Seamless integration with ASP.NET Core logging and configuration
- ✅ Interface-based dependency injection (
IBlinkDebitClient) - ✅ Supports both
appsettings.jsonand programmatic configuration
Manual Dependency Injection (Legacy)
The client code can use .NET dependency injection manually:
// configure dependency injection
var serviceCollection = new ServiceCollection();
// configure path to appsettings.json
var basePath = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..");
var config = new ConfigurationBuilder()
.SetBasePath(basePath)
.AddJsonFile("appsettings.json")
.Build();
// configure BlinkPayProperties
serviceCollection.Configure<BlinkPayProperties>(config.GetSection("BlinkPay"));
serviceCollection.AddSingleton(resolver => resolver.GetRequiredService<IOptions<BlinkPayProperties>>().Value);
// configure logger
serviceCollection.AddLogging(builder =>
{
builder
.AddConsole() // use file logging
.AddDebug(); // use information
});
var serviceProvider = serviceCollection.BuildServiceProvider();
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("BlinkDebitClient");
serviceCollection.AddSingleton(logger);
// create BlinkDebitClient
serviceCollection.AddSingleton<BlinkDebitClient>();
serviceProvider = serviceCollection.BuildServiceProvider();
// retrieve BlinkDebitClient
var client = serviceProvider.GetService<BlinkDebitClient>();
Direct Instantiation
Another way is to supply the required values during object creation:
// configure logger
var logger = LoggerFactory
.Create(builder => builder
.AddConsole() // use file logging
.AddDebug()) // use information
.CreateLogger<MyProgram>();
// configure path to appsettings.json
var basePath = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..");
var config = new ConfigurationBuilder()
.SetBasePath(basePath)
.AddJsonFile("appsettings.json")
.Build();
// bind BlinkPay settings section to BlinkPayProperties
var blinkPayProperties = new BlinkPayProperties();
config.GetSection("BlinkPay").Bind(blinkPayProperties);
// create BlinkDebitClient
var client = new BlinkDebitClient(logger, blinkPayProperties);
// or
// var client = new BlinkDebitClient(logger, blinkPayProperties.DebitUrl, blinkPayProperties.ClientId, blinkPayProperties.ClientSecret);
Request ID, Correlation ID and Idempotency Key
An optional request ID, correlation ID and idempotency key can be added as arguments to API calls. They will be generated for you automatically if they are not provided.
A request can have one request ID and one idempotency key but multiple correlation IDs in case of retries.
The idempotency key is what makes a retried creation safe, so it is worth supplying your own whenever
your application — rather than the SDK — is the one retrying. See Refund idempotency
for the rules that apply to POST /refunds; consent and payment creation take the same header.
Full Examples
Note: For error handling, a BlinkServiceException can be caught.
Quick payment (one-off payment), using Gateway flow
A quick payment is a one-off payment that combines the API calls needed for both the consent and the payment.
var gatewayFlow = new GatewayFlow("https://www.blinkpay.co.nz/sample-merchant-return-page");
var authFlowDetail = new AuthFlowDetail(gatewayFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr("particulars", "code", "reference");
var amount = new Amount("0.01", Amount.CurrencyEnum.NZD);
var request = new QuickPaymentRequest(authFlow, pcr, amount);
var qpCreateResponse = await client.CreateQuickPaymentAsync(request);
_logger.LogInformation("Redirect URL: {}", qpCreateResponse.RedirectUri); // Redirect the consumer to this URL
var qpId = qpCreateResponse.QuickPaymentId;
var qpResponse = await client.AwaitSuccessfulQuickPaymentAsync(qpId, 300); // Will throw an exception if the payment was not successful after 5min
Single consent followed by one-off payment, using Gateway flow
var redirectFlow = new RedirectFlow("https://www.blinkpay.co.nz/sample-merchant-return-page", Bank.BNZ);
var authFlowDetail = new AuthFlowDetail(redirectFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr("particulars");
var amount = new Amount("0.01", Amount.CurrencyEnum.NZD);
var request = new SingleConsentRequest(authFlow, pcr, amount);
var createConsentResponse = await client.CreateSingleConsentAsync(request);
var redirectUri = createConsentResponse.RedirectUri; // Redirect the consumer to this URL
var paymentRequest = new PaymentRequest
{
ConsentId = createConsentResponse.ConsentId
};
var paymentResponse = await client.CreatePaymentAsync(paymentRequest);
_logger.LogInformation("Payment Status: {}", (await client.GetPaymentAsync(paymentResponse.PaymentId)).Status);
// TODO inspect the payment result status
Polling and Timeout Behavior
The SDK provides helper methods to wait for consent authorization and payment completion. Understanding the auto-revoke behavior is critical for proper implementation.
Auto-Revoke on Timeout
| Method | Auto-Revokes on Timeout? | Reason |
|---|---|---|
AwaitSuccessfulQuickPaymentAsync |
✅ YES | Quick payments combine consent + payment - should complete immediately or be cancelled |
AwaitAuthorisedSingleConsentAsync |
❌ NO | Single consents require separate payment step - no funds processed if abandoned |
AwaitAuthorisedEnduringConsentAsync |
✅ YES | Enduring consents grant ongoing access - clean up if abandoned for security |
AwaitSuccessfulPaymentAsync |
❌ N/A | Payments cannot be revoked once initiated |
Best Practices:
- Manually revoke single or enduring consents if you determine the customer has permanently abandoned the authorization flow (before timeout expires)
- Enduring consents will auto-revoke on timeout, but earlier manual revocation improves security
Payment Settlement and Wash-up Process
Important: Payment settlement is asynchronous. Payments transition through these states:
Settlement Statuses:
Pending- Payment initiated, not yet settledAcceptedSettlementInProcess- Settlement in progressAcceptedSettlementCompleted- ✅ ONLY THIS STATUS means money has been sent from the payer's bankRejected- Payment failed
Wash-up Implementation:
// Poll payment status until settlement completes
public async Task<Payment> WaitForSettlement(Guid paymentId, int maxAttempts = 60)
{
for (int i = 0; i < maxAttempts; i++)
{
var payment = await client.GetPaymentAsync(paymentId);
if (payment.Status == Payment.StatusEnum.AcceptedSettlementCompleted)
{
return payment; // SUCCESS - funds sent from payer's bank
}
if (payment.Status == Payment.StatusEnum.Rejected)
{
throw new Exception("Payment rejected");
}
await Task.Delay(5000); // Wait 5 seconds between checks
}
throw new Exception("Payment settlement timeout");
}
Only AcceptedSettlementCompleted confirms funds have been sent from the payer's bank. In rare cases, payments may remain in AcceptedSettlementInProcess for extended periods.
Individual API Call Examples
Bank Metadata
Supplies the supported banks and supported flows on your account.
var bankMetadataList = await client.GetMetaAsync();
Quick Payments
Gateway Flow
var gatewayFlow = new GatewayFlow(redirectUri);
var authFlowDetail = new AuthFlowDetail(gatewayFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr(particulars, code, reference);
var amount = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new QuickPaymentRequest(authFlow, pcr, amount);
var createQuickPaymentResponse = await client.CreateQuickPaymentAsync(request);
Gateway Flow - Redirect Flow Hint
var redirectFlowHint = new RedirectFlowHint(bank);
var flowHint = new GatewayFlowAllOfFlowHint(redirectFlowHint);
var gatewayFlow = new GatewayFlow(redirectUri, flowHint);
var authFlowDetail = new AuthFlowDetail(gatewayFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr(particulars, code, reference);
var amount = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new QuickPaymentRequest(authFlow, pcr, amount);
var createQuickPaymentResponse = await client.CreateQuickPaymentAsync(request);
Gateway Flow - Decoupled Flow Hint
var decoupledFlowHint = new DecoupledFlowHint(bank, identifierType, identifierValue);
var flowHint = new GatewayFlowAllOfFlowHint(decoupledFlowHint);
var gatewayFlow = new GatewayFlow(redirectUri, flowHint);
var authFlowDetail = new AuthFlowDetail(gatewayFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr(particulars, code, reference);
var amount = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new QuickPaymentRequest(authFlow, pcr, amount);
var createQuickPaymentResponse = await client.CreateQuickPaymentAsync(request);
Redirect Flow
var redirectFlow = new RedirectFlow(redirectUri, bank);
var authFlowDetail = new AuthFlowDetail(redirectFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr(particulars, code, reference);
var amount = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new QuickPaymentRequest(authFlow, pcr, amount);
var createQuickPaymentResponse = await client.CreateQuickPaymentAsync(request);
Decoupled Flow
var decoupledFlow = new DecoupledFlow(bank, identifierType, identifierValue, callbackUrl);
var authFlowDetail = new AuthFlowDetail(decoupledFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr(particulars, code, reference);
var amount = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new QuickPaymentRequest(authFlow, pcr, amount);
var createQuickPaymentResponse = await client.CreateQuickPaymentAsync(request);
Retrieval
var quickPaymentResponse = await client.GetQuickPaymentAsync(quickPaymentId);
Revocation
await client.RevokeQuickPaymentAsync(quickPaymentId);
Single/One-Off Consents
Gateway Flow
var gatewayFlow = new GatewayFlow(redirectUri);
var authFlowDetail = new AuthFlowDetail(gatewayFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr(particulars, code, reference);
var amount = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new SingleConsentRequest(authFlow, pcr, amount);
var createConsentResponse = await client.CreateSingleConsentAsync(request);
Gateway Flow - Redirect Flow Hint
var redirectFlowHint = new RedirectFlowHint(bank);
var flowHint = new GatewayFlowAllOfFlowHint(redirectFlowHint);
var gatewayFlow = new GatewayFlow(redirectUri, flowHint);
var authFlowDetail = new AuthFlowDetail(gatewayFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr(particulars, code, reference);
var amount = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new SingleConsentRequest(authFlow, pcr, amount);
var createConsentResponse = await client.CreateSingleConsentAsync(request);
Gateway Flow - Decoupled Flow Hint
var decoupledFlowHint = new DecoupledFlowHint(bank, identifierType, identifierValue);
var flowHint = new GatewayFlowAllOfFlowHint(decoupledFlowHint);
var gatewayFlow = new GatewayFlow(redirectUri, flowHint);
var authFlowDetail = new AuthFlowDetail(gatewayFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr(particulars, code, reference);
var amount = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new SingleConsentRequest(authFlow, pcr, amount);
CreateConsentResponse createConsentResponse = await client.CreateSingleConsentAsync(request);
Redirect Flow
Suitable for most consents.
var redirectFlow = new RedirectFlow(redirectUri, bank);
var authFlowDetail = new AuthFlowDetail(redirectFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr(particulars, code, reference);
var amount = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new SingleConsentRequest(authFlow, pcr, amount);
var createConsentResponse = await client.CreateSingleConsentAsync(request);
Decoupled Flow
This flow type allows better support for mobile by allowing the supply of a mobile number or previous consent ID to identify the customer with their bank.
The customer will receive the consent request directly to their online banking app. This flow does not send the user through a web redirect flow.
var decoupledFlow = new DecoupledFlow(bank, identifierType, identifierValue, callbackUrl);
var authFlowDetail = new AuthFlowDetail(decoupledFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr(particulars, code, reference);
var amount = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new SingleConsentRequest(authFlow, pcr, amount);
var createConsentResponse = await client.CreateSingleConsentAsync(request);
Retrieval
Get the consent including its status
var consent = await client.GetSingleConsentAsync(consentId);
Revocation
await client.RevokeSingleConsentAsync(consentId);
Blink AutoPay - Enduring/Recurring Consents
Request an ongoing authorisation from the customer to debit their account on a recurring basis.
Note that such an authorisation can be revoked by the customer in their mobile banking app.
Gateway Flow
var gatewayFlow = new GatewayFlow(redirectUri);
var authFlowDetail = new AuthFlowDetail(gatewayFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr(particulars, code, reference);
var maximumAmountPeriod = new Amount(total, Amount.CurrencyEnum.NZD);
var maximumAmountPayment = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new EnduringConsentRequest(authFlow, startDate, endDate, period, maximumAmountPeriod, maximumAmountPayment, hashedCustomerIdentifier);
var createConsentResponse = await client.CreateEnduringConsentAsync(request);
Gateway Flow - Redirect Flow Hint
var redirectFlowHint = new RedirectFlowHint(bank);
var flowHint = new GatewayFlowAllOfFlowHint(redirectFlowHint);
var gatewayFlow = new GatewayFlow(redirectUri, flowHint);
var authFlowDetail = new AuthFlowDetail(gatewayFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr(particulars, code, reference);
var maximumAmountPeriod = new Amount(total, Amount.CurrencyEnum.NZD);
var maximumAmountPayment = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new EnduringConsentRequest(authFlow, startDate, endDate, period, maximumAmountPeriod, maximumAmountPayment, hashedCustomerIdentifier);
var createConsentResponse = await client.CreateEnduringConsentAsync(request);
Gateway Flow - Decoupled Flow Hint
var decoupledFlowHint = new DecoupledFlowHint(bank, identifierType, identifierValue);
var flowHint = new GatewayFlowAllOfFlowHint(decoupledFlowHint);
var gatewayFlow = new GatewayFlow(redirectUri, flowHint);
var authFlowDetail = new AuthFlowDetail(gatewayFlow);
var authFlow = new AuthFlow(authFlowDetail);
var pcr = new Pcr(particulars, code, reference);
var maximumAmountPeriod = new Amount(total, Amount.CurrencyEnum.NZD);
var maximumAmountPayment = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new EnduringConsentRequest(authFlow, startDate, endDate, period, maximumAmountPeriod, maximumAmountPayment, hashedCustomerIdentifier);
var createConsentResponse = await client.CreateEnduringConsentAsync(request);
Redirect Flow
var redirectFlow = new RedirectFlow(redirectUri, bank);
var authFlowDetail = new AuthFlowDetail(redirectFlow);
var authFlow = new AuthFlow(authFlowDetail);
var maximumAmountPeriod = new Amount(total, Amount.CurrencyEnum.NZD);
var maximumAmountPayment = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new EnduringConsentRequest(authFlow, startDate, endDate, period, maximumAmountPeriod, maximumAmountPayment, hashedCustomerIdentifier);
var createConsentResponse = await client.CreateEnduringConsentAsync(request);
Decoupled Flow
var decoupledFlow = new DecoupledFlow(bank, identifierType, identifierValue, callbackUrl);
var authFlowDetail = new AuthFlowDetail(decoupledFlow);
var authFlow = new AuthFlow(authFlowDetail);
var maximumAmountPeriod = new Amount(total, Amount.CurrencyEnum.NZD);
var maximumAmountPayment = new Amount(total, Amount.CurrencyEnum.NZD);
var request = new EnduringConsentRequest(authFlow, startDate, endDate, period, maximumAmountPeriod, maximumAmountPayment, hashedCustomerIdentifier);
var createConsentResponse = await client.CreateEnduringConsentAsync(request);
Retrieval
var consent = await client.GetEnduringConsentAsync(consentId);
Revocation
await client.RevokeEnduringConsentAsync(consentId);
Payments
The completion of a payment requires a consent to be in the Authorised status.
Single/One-Off
var paymentRequest = new PaymentRequest
{
ConsentId = consentId
};
var paymentResponse = await client.CreatePaymentAsync(request);
Enduring/Recurring
If you already have an approved consent, you can run a Payment against that consent at the frequency as authorised in the consent.
var pcr = new Pcr(particulars, code, reference);
var amount = new Amount(total, Amount.CurrencyEnum.NZD);
var paymentRequest = new PaymentRequest(consentId, pcr, amount);
var paymentResponse = await client.CreatePaymentAsync(request);
Retrieval
var payment = await client.GetPaymentAsync(paymentId);
Refunds
Account Number Refund
var request = new AccountNumberRefundRequest(paymentId);
var refundResponse = await client.CreateRefundAsync(request);
Full Refund (Not yet implemented)
var pcr = new Pcr(particulars, code, reference);
var request = new FullRefundRequest(paymentId, pcr, redirectUri);
var refundResponse = await client.CreateRefundAsync(request);
Partial Refund (Not yet implemented)
var amount = new Amount(total, Amount.CurrencyEnum.NZD);
var pcr = new Pcr(particulars, code, reference);
var request = new PartialRefundRequest(paymentId, amount pcr, redirectUri);
var refundResponse = await client.CreateRefundAsync(request);
Idempotency
All three refund requests above accept an idempotency-key header. The SDK generates one per call if
you omit it, which covers the retries it makes on your behalf — but a key it generated is gone by the
time a failure reaches you, so a retry your own application makes is a second, unrelated refund. Hold
your own key and send the same one:
var request = new AccountNumberRefundRequest(paymentId);
var requestHeaders = new Dictionary<string, string?>
{
// Store this alongside the refund attempt and reuse it if you retry
["idempotency-key"] = idempotencyKey
};
var refundResponse = await client.CreateRefundAsync(request, requestHeaders);
What Blink Debit does with the key on POST /refunds (API spec 1.0.60):
| Request | Result |
|---|---|
| Same key, same payload | The original 201 is replayed, carrying the original refund_id. No second refund is created. |
| Same key, different payload | Rejected with 409 BP702. |
| Same key while the first request is still in flight | Rejected with 409 BP711. Retry once the first request settles. |
| No key | No de-duplication at all — a blind retry refunds the customer twice. |
The SDK's retry policy re-sends the request it already built, so the key is stable across any attempt
it makes. It does not retry HTTP errors, though — a response only becomes an exception after the
policy has finished — so a 5xx reaches you having been sent once. Whether to retry it is your
decision, and it is the case where holding your own key matters.
Retrieval
var refund = await client.GetRefundAsync(refundId);
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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 was computed. 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 is compatible. 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. |
-
net10.0
- JsonSubTypes (>= 2.1.0)
- Microsoft.Extensions.Configuration (>= 10.0.12)
- Microsoft.Extensions.Configuration.Binder (>= 10.0.12)
- Microsoft.Extensions.Configuration.FileExtensions (>= 10.0.12)
- Microsoft.Extensions.Configuration.Json (>= 10.0.12)
- Microsoft.Extensions.Logging (>= 10.0.12)
- Newtonsoft.Json (>= 13.0.4)
- Polly (>= 8.7.0)
- Polly.Contrib.WaitAndRetry (>= 1.1.1)
- RestSharp (>= 114.0.0)
- System.ComponentModel.Annotations (>= 5.0.0)
-
net8.0
- JsonSubTypes (>= 2.1.0)
- Microsoft.Extensions.Configuration (>= 10.0.12)
- Microsoft.Extensions.Configuration.Binder (>= 10.0.12)
- Microsoft.Extensions.Configuration.FileExtensions (>= 10.0.12)
- Microsoft.Extensions.Configuration.Json (>= 10.0.12)
- Microsoft.Extensions.Logging (>= 10.0.12)
- Newtonsoft.Json (>= 13.0.4)
- Polly (>= 8.7.0)
- Polly.Contrib.WaitAndRetry (>= 1.1.1)
- RestSharp (>= 114.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on BlinkDebitApiClient:
| Package | Downloads |
|---|---|
|
BlinkDebitApiClient.Extensions.DependencyInjection
Dependency Injection extensions for BlinkDebitApiClient to enable seamless integration with ASP.NET Core and other .NET applications using Microsoft.Extensions.DependencyInjection |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 1.8.4 | 76 | 9/22/2026 | |
| 1.8.3 | 94 | 9/16/2026 | |
| 1.8.2 | 105 | 9/15/2026 | |
| 1.8.1 | 104 | 9/13/2026 | |
| 1.8.0 | 123 | 9/1/2026 | |
| 1.7.0 | 145 | 7/29/2026 | |
| 1.6.0 | 428 | 11/17/2025 | |
| 1.5.0 | 382 | 11/16/2025 | |
| 1.4.0 | 256 | 11/7/2025 | |
| 1.3.1 | 258 | 10/13/2025 | |
| 1.3.0 | 270 | 5/23/2025 | |
| 1.2.0 | 317 | 3/26/2025 | |
| 1.1.1 | 247 | 10/30/2024 | |
| 1.1.0 | 242 | 10/22/2024 | |
| 1.0.2 | 380 | 7/24/2023 | |
| 1.0.1 | 319 | 6/22/2023 | |
| 1.0.0 | 335 | 6/20/2023 |