SilverLabs.SilverDotPay.Sdk 1.9.0
SilverDotPay SDK
Typed .NET client for the SilverDotPay payment gateway.
Install
dotnet add package SilverLabs.SilverDotPay.Sdk
The SilverLABS NuGet feed must be configured. In nuget.config:
<add key="silverlabs" value="https://nuget.silverlabs.uk/v3/index.json" />
Quick start
services.AddSilverDotPaySdk(opts =>
{
opts.BaseAddress = "https://silverdotpay.silverlabs.uk";
opts.Mode = SilverDotPayClientMode.ApiKey;
opts.ApiKey = configuration["SilverDotPay:ApiKey"];
opts.Timeout = TimeSpan.FromSeconds(30);
})
.AddPublicClient() // currencies + exchange rates (the server still requires X-API-Key on these routes)
.AddMerchantClient() // orders, own API keys, Stripe Connect
.AddAdminClient() // applications, keys, webhook secrets, settings, Stripe Connect
.AddCardClient(); // card rail: charge-saved, setup, saved cards, reconcile (1.3.0+)
Then inject any of:
ISilverDotPayClient— narrow legacy surface (order create, get). Its escrow members call parked routes (404) and go in 2.0 (see "Towards 2.0").ISilverDotPayPublicClient— currencies, exchange rates. Despite the name, the server requires an API key on these routes today; configure the client inApiKeymode.ISilverDotPayMerchantClient— orders, the application's own API keys, Stripe Connect. Balance and withdrawal members are[Obsolete]; the escrow members call parked routes (404) and go in 2.0.ISilverDotPayAdminClient— applications (incl.WalletMode,ExtendedPublicKeys), API keys, webhook secret rotation and delivery log, settings, Stripe Connect. Balance members are[Obsolete]; the escrow members call parked routes (404) and go in 2.0.ISilverDotPayCardClient— card rail: rail status, charge saved card, setup-mode capture, list/remove saved cards, reconcile.
Auth modes
Pick one per HttpClient:
SilverDotPayClientMode.ApiKey— setsX-API-Keyheader fromopts.ApiKey. Used by service accounts and admin keys.SilverDotPayClientMode.PassportBearer— forwards a Passport SSO token from a pluggableITokenSource. Used in ASP.NET Core hosts where the inbound user's token is propagated downstream.
Inbound webhook validation
services.AddSingleton<ISilverDotPayWebhookValidator>(sp =>
new SilverDotPayWebhookValidator(secret: cfg["SilverDotPay:WebhookSecret"], logger));
Validator parses X-SilverDotPay-Signature: t=<unix>,v1=<hex>, recomputes
HMAC-SHA256("<unix>.<raw body>", secret), and rejects if the timestamp falls
outside a 5-minute replay window. Fails closed when no secret is configured.
See docs/WEBHOOKS.md in the silverdotpay repo for the wire format.
Card rail (1.3.0)
- Card checkout:
CreateOrderAsyncwithRail = SilverDotPayRail.Card, GBPAmount,BuyerIdentifier(tenant id),SuccessUrl,CancelUrl; redirect the buyer toCreateOrderResponse.PaymentUrl. The card is saved for renewals. payment_confirmedcarriespayment_method.ref— store it and pass it asPaymentMethodReftoISilverDotPayCardClient.ChargeSavedAsyncfor renewals (optionally withBuyerIdentifieras an ownership check). Use a newExternalOrderIdper attempt; reuse it only to retry the same attempt (never double-charges).ChargeSavedResponse.Statusis one ofSilverDotPayChargeStatus.processingmeans the outcome is unknown: do not treat it as failed and do not start another attempt; reconcile viaPOST /api/orders/{id}/reconcile.payment_failedcarriesfailure.reason(SilverDotPayFailureReason) and, forauthentication_required,failure.action_url— send the customer there to authenticate.payment_method_saved(setup mode) has noorder; key it onpayment_method.buyer_identifier.- A 503 (
SilverDotPayException.StatusCode == 503) orGetCardRailStatusAsync().IsConfigured == falsemeans cards are not configured for this application: hide the card option.
1.5.0 (additive)
livemodeonCreateOrderResponse,OrderStatusResponseand the webhookorder: the Stripe livemode of the completing payment (false= test mode). Null until paid, for crypto orders, or from a SilverDotPay older than this SDK. Consumers must not provision from afalsepayment outside a designated test tenant. A null on a paid card order means unknown: hold it for a person rather than provisioning, and never read null as test mode.ISilverDotPayCardClient.ReconcileOrderAsync(orderId): asks SilverDotPay to reconcile a card order with Stripe (missed-webhook recovery) and returns the order; 404/503 surface asSilverDotPayException.
1.6.0 (additive)
- Stripe Connect calls:
ISilverDotPayMerchantClientandISilverDotPayAdminClient(leadingapplicationId) gainStartStripeConnectAsync,CompleteStripeConnectAsync(StripeConnectCompleteRequest),GetStripeConnectStatusAsyncandDisconnectStripeAsync, returningStripeConnectStartDto/StripeConnectStatusDto. ApplicationDto+=StripeConnectedAccountId,StripeConnectLivemode,StripeConnectedAtUtc,StripeChargesOnPlatform.UpdateApplicationRequest+=WalletMode,ExtendedPublicKeys.- Fix:
RotateWebhookSecretAsyncnow POSTs to.../webhook-secret/rotate(the previous path did not match the API action). - Obsolete (still functional, removal scheduled for SDK 2.0):
GetMyBalancesAsync,RequestWithdrawalAsync,ListWithdrawalsAsync,GetGlobalBalancesAsync,GetApplicationBalancesAsync. Custodial surfaces are parked.
1.7.0 (additive)
CreateApplicationRequest.WalletModeis nowint?. Omitted means WatchOnly, the Silver Pay Stage 6 default: a non-custodial, card-only application needs no extended public keys. Set1(WatchOnly) explicitly if you prefer;0(PlatformCustody) is first-party only.- Behaviour change on the server (not the SDK): the custodial surfaces (balances, escrow) answer 404 while
Platform:CustodialFeaturesEnabledis off, and custody-mode crypto orders are refused with 503 for non-first-party applications. The[Obsolete]custodial members remain for source compatibility. - Server-side since Silver Pay Stage 7 (no SDK change): a
WatchOnlyapplication takes BTC/LTC/ETH with its own account-level extended public keys, set throughUpdateApplicationRequest.ExtendedPublicKeys(JSON{"BTC":"zpub…","LTC":"zpub…","ETH":"xpub…"}; Litecoin native segwit shares thezpubprefix,Mtubis wrapped segwit;{}clears). Invalid keys → 400Invalid extended public keys: …; a crypto order without a usable key for the coin → 503 naming the problem. The application response now carrieswatchOnlyFirstAddresses(not yet onApplicationDto; planned for the next SDK minor together withExtendedPublicKeys). The BTCPay webhook route is gone.
1.8.0 (additive)
ApplicationDto+=ExtendedPublicKeys(the stored JSON map) andWatchOnlyFirstAddresses(Silver Pay Stage 7: the0/0address per stored key for a WatchOnly application, so a console can show the merchant what to compare with their wallet). Both null when absent; older servers simply leave them null.
1.9.0 (additive)
CreateOrderResponseandOrderStatusResponse+=DerivationPath: for an order of a WatchOnly application, the merchant key's derivation pathxo:{fingerprint}/0/{index}so a console or wallet integration can track the address index. Null for card orders, platform-custody orders and older servers.
Towards 2.0
The custodial gateway is parked on the server (Platform:CustodialFeaturesEnabled=false, Silver Pay Stage 6). Its balance and withdrawal SDK members are [Obsolete]; the escrow members are not marked but call routes that answer 404. SDK 2.0 removes all of them. Plan for 2.0 by not calling:
- Merchant client:
GetMyBalancesAsync,RequestWithdrawalAsync,ListWithdrawalsAsync,ReleaseEscrowAsync,RefundEscrowAsync. - Admin client:
GetGlobalBalancesAsync,GetApplicationBalancesAsync,AdminReleaseEscrowAsync,AdminRefundEscrowAsync. - Legacy
ISilverDotPayClient:ReleaseEscrowAsync,RefundEscrowAsync. - Webhook models for
escrow_*,payment_detected,overpayment_detectedandunderpayment_detected: no live rail sends those events (the hdwallet rail sendspayment_seen,payment_confirming,payment_confirmed,payment_underpaidwith asettlementblock; the card rail sendspayment_confirmed,payment_failed,payment_method_saved).order_expiredis sent by both rails and stays.
Everything else (orders with Rail, Livemode, card client, Stripe Connect, applications with WalletMode/ExtendedPublicKeys/WatchOnlyFirstAddresses, keys, webhook secrets, settings, the webhook validator) carries into 2.0 unchanged. Wire format and routes are documented in docs/API-INTEGRATION.md and docs/WEBHOOKS.md of the silverdotpay repo.
Versioning
SemVer. Major versions track breaking API contract changes on the silverdotpay backend.
No packages depend on SilverLabs.SilverDotPay.Sdk.
.NET 9.0
- Microsoft.Extensions.Http (>= 9.0.10)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.10)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 9.0.10)