ASP.NET Core
Lunixi.Sdk 0.1.1 is published on NuGet (opens in a new tab). The downloaded public package, source commit and NuGet catalog SHA-512 were verified on 31 October 2026.
Version 0.1.1 includes a concrete merchant-site presentation example. Embedded checkout is the default: load only the official Lunixi bundle and mount the existing form; methods and multi-card choices stay in the Lunixi panel. Optional hosted mode uses the backend paymentPageUrl after exact HTTPS pay.lunixi.com/payment/ validation. Its token may differ from the embedded token. Missing URLs keep embedded available and hosted on hold/reconciliation with the original attempt/key. Never derive a URL from the browser token. Authorize the customer/order and native browser CSRF before rendering, send Cache-Control: private, no-store, preserve the merchant CSP nonce and keep tokens/HTML/redirect URLs out of logs. Generic response data preserves paymentPageUrl; no new typed product parity is claimed.
The .NET / C# SDK repository includes a runnable ASP.NET Core 8 backend at samples/AspNetCore (opens in a new tab). It uses Minimal APIs, the shared SDK and native SQLite to demonstrate server-priced hosted intent creation, durable idempotency keys and atomic webhook/order updates. This is an application example, not a separate NuGet framework package.
The sample is a trusted backend API protected by an explicitly configured bearer token. It does not provide customer login or per-customer ownership. Keep that backend token out of browser/mobile clients; replace it with your native identity and order permissions when adapting the application. If you introduce browser cookie authentication, add the appropriate ASP.NET Core antiforgery policy to state-changing customer/admin routes.
Install the SDK in your ASP.NET Core project
dotnet add package Lunixi.Sdk --version 0.1.1 --source https://api.nuget.org/v3/index.jsonThe published SDK is a dependency for your application. The runnable example below remains source code in the SDK repository, with its own SQLite/backend authorization setup.
Run from source
Use a runtime/SDK compatible with the declared net8.0 project target. Clone the SDK source and run the existing project; its project reference uses the SDK in the same checkout. This source workflow remains available alongside the published NuGet package.
git clone https://github.com/Lunixi-Payment/lunixi-dotnet.git
cd lunixi-dotnet
dotnet restore samples/AspNetCore/AspNetCore.csproj --locked-mode
dotnet run --project samples/AspNetCore/AspNetCore.csproj --urls http://127.0.0.1:5080Configure these server variables through your secret provider or shell before starting:
| Variable | Value |
|---|---|
LUNIXI_BASE_URL | https://api-gateway.lunixi.com |
LUNIXI_MERCHANT_ID | Expected merchant identity in authenticated payment records |
LUNIXI_KEY_ID | Registered merchant TEST secret-key identifier |
LUNIXI_PRIVATE_KEY_PEM | Ed25519 PKCS#8 private PEM with real newlines |
LUNIXI_WEBHOOK_SECRET | Endpoint signing secret |
DEMO_API_TOKEN | Independently generated random backend access token, at least 32 characters |
LUNIXI_DATABASE_PATH | Absolute private writable SQLite path on persistent storage |
MERCHANT_CALLBACK_URL | Your public HTTPS /payments/return address |
The development listener is loopback HTTP. Real TEST checkout needs public HTTPS/TLS termination and a registered https://your-host/webhooks/lunixi connection. Secrets, tokens and database files stay outside source control. The sample creates its SQLite schema and one DEMO-1001 order at startup; replace demo initialization with reviewed application migrations before deployment.
Routes and flow
| Route | Behavior |
|---|---|
GET /health | Readiness information only |
POST /checkout/DEMO-1001 | Backend bearer token; loads 10050 TRY minor units from SQLite and persists attempt key before network |
GET /orders/DEMO-1001 | Same backend authorization; reads native state |
GET/POST /payments/return | Informational only, no payment-state authority |
POST /webhooks/lunixi | Bounded original raw bytes, v2 signature and authenticated payment GET |
Call checkout from your trusted backend with Authorization: Bearer <DEMO_API_TOKEN>. Submitted request-body prices are ignored. The actual gateway envelope contains data.paymentId and data.token; hand the token to the intended authenticated checkout using the existing Lunixi form. The sample does not build a card form or store raw card data. Do not log the response body or expose the backend access token to that checkout.
Repeated checkout requests reuse the original database attempt/key across restarts. After 23 hours, the application requires reconciliation instead of replaying a potentially expired gateway key. A pending response is not capture proof; do not replace an uncertain key with a new one.
Webhook settlement and persistence
The webhook reads at most 1 MiB, preserves signature header values, verifies the raw delivery and locates only a payment already bound to a local order. It then authenticates GET and matches payment ID, configured merchant ID, order reference, exact amount, currency and complete captured/refunded balances.
Only complete capture with zero refunds marks paid. Authorization stays on hold. Event/browser status alone never triggers fulfillment. A later stale GET cannot roll back an already recorded refund. The event ID and raw payload hash are durable: identical committed deliveries are acknowledged, changed content for the same ID is rejected, and order/inbox writes commit together in the same SQLite transaction. Invalid signatures return 400; missing/mismatched settlement returns 503 for reconciliation.
Explicit boundaries
- The static backend token and seeded order demonstrate wiring; they do not replace production customer authorization, native order pricing or a permission system.
- Ordinary capture/authorization/refund reads are covered. Split settlements, split-leg delivery and promissory-note capture fail closed pending application-specific policy.
- Final captured amount must equal the stored order total. For installment fees, insurance premiums, partial capture or other adjusted totals, persist/validate the approved amount and separate fulfillment from provider/insurance state before enabling them.
- Add missed-webhook/background reconciliation, overdue-attempt review, inbox retention/monitoring and refund/dispute workflows before production. The sample does not invent external fulfillment/email effects.
- SQLite is the runnable single-store example. Distributed production workers need tested native database locking, isolation and atomic event/order writes on persistent storage.
The SDK's other clients and low-level operation APIs are documented in the .NET SDK guide; this page does not duplicate their implementation or claim every SDK surface is wired into this sample.
Verification
dotnet test tests/Lunixi.Sdk.Tests/Lunixi.Sdk.Tests.csproj -c Release --filter "FullyQualifiedName~AspNetCore"The repository's ASP.NET Core TestServer suites exercise real framework routing and native SQLite with deterministic gateway transport. Cases include backend authorization, server totals, stable keys, malformed create response identities, signed/duplicate/conflicting deliveries, untrusted browser returns, amount mismatch and durable settlement state. These tests make no live gateway payment call. Complete a registered TEST-merchant payment and genuine webhook against your public HTTPS deployment before accepting real payments.
References: Microsoft Minimal APIs (opens in a new tab), integration testing (opens in a new tab), antiforgery (opens in a new tab), sample source and setup (opens in a new tab).
Merchant-page integration example
The runnable ASP.NET Core sample now exposes authenticated POST /checkout/{orderId}/form for embedded HTML by default; ?mode=hosted uses the validated backend URL. The existing /checkout/{orderId} JSON contract is retained. Lunixi.AspNetCoreSample.CheckoutPresentation contains the renderer and URL validator. DEMO_API_TOKEN remains strictly server-to-server: never send it to browser JavaScript. Your merchant checkout controller must authenticate the customer, verify order ownership and native CSRF before proxying/rendering this response. This sample does not implement customer login or a production tenant authorization model.