Installation & Package Setup

Install NordAPI.Swish from NuGet. The package targets .NET 8+ and includes all required dependencies for mTLS transport and webhook verification.

PowerShell
dotnet add package NordAPI.Swish

Or add via PackageReference in your .csproj. Pin a concrete version for production deployments.

SwishClient Initialization

Register the Swish client in your dependency injection container using AddSwishClient. Configuration is driven by environment variables. For local development, fallback values are acceptable; in production, use secrets management and remove all fallbacks.

C#
using NordAPI.Swish;
using NordAPI.Swish.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);

// Register the Swish client using environment variables
builder.Services.AddSwishClient(opts =>
{
    opts.BaseAddress = new Uri(Environment.GetEnvironmentVariable("SWISH_BASE_URL")
        ?? "https://example.invalid");
    opts.ApiKey = Environment.GetEnvironmentVariable("SWISH_API_KEY")
        ?? "dev-key";
    opts.Secret = Environment.GetEnvironmentVariable("SWISH_SECRET")
        ?? "dev-secret";
});

The client is injected via ISwishClient and provides methods for payments, refunds, and status polling.

mTLS & Transport Layer Security

The SDK enforces mTLS by default. Client certificates are configured via environment variables. If RequireMtls = true (default) and no certificate is found, the SDK throws SwishConfigurationException during handler creation.

  • SWISH_PFX_PATH — Path to the client certificate (.pfx)
  • SWISH_PFX_PASSWORD — Certificate password

In Debug builds, server certificate validation is relaxed for local testing. In Release builds, strict certificate chain validation is enforced. Set RequireMtls = false only for controlled mock environments.

Deterministic Webhook Verification

NordAPI provides an optional webhook hardening pattern using HMAC-SHA256 signatures. Your webhook endpoint must verify the signature before processing any callback.

Important

X-Swish-Signature, X-Swish-Timestamp, and X-Swish-Nonce are NordAPI hardening headers, not official Swish callback baseline. You add these at your edge layer.

Canonical String Format

The signature is computed as Base64-encoded HMAC-SHA256 over a canonical string. The canonical string is constructed as:

FORMAT
<timestamp>\n<nonce>\n<body>

Where \n is a literal newline character (0x0A). The body must be the exact raw UTF-8 bytes of the request body with no modification.

Verification Rules

  • Timestamps must be Unix seconds (not milliseconds)
  • Reject requests where timestamp age exceeds 10 minutes
  • Use exact raw body bytes — any whitespace changes break verification
  • Compare signatures using constant-time comparison
  • Reject on any mismatch; fail closed

Default verification limits are 5 minutes for allowed clock skew and 10 minutes for maximum message age.

Bash
# Generate signature for testing
ts="$(date +%s)"
nonce="$(uuidgen)"
body='{"event":"payment_received","paymentId":"pay_123456"}'

canonical="$(printf "%s\n%s\n%s" "$ts" "$nonce" "$body")"
sig="$(printf "%s" "$canonical" | openssl dgst -sha256 -hmac "$SWISH_WEBHOOK_SECRET" -binary | openssl base64)"

Nonce Store & Replay Protection

Replay protection prevents attackers from re-submitting captured webhook requests. The SDK tracks seen nonces and rejects duplicates with HTTP 409.

  • Development: In-memory nonce store is acceptable for single-instance local testing
  • Production: Use a persistent store (Redis or database). Set SWISH_REDIS, REDIS_URL, or SWISH_REDIS_CONN

The sample application fails fast in Production environment if no persistent nonce store is configured.

Fail-closed Behavior

The SDK is designed to fail closed on security-sensitive operations. Invalid or missing configuration does not result in degraded operation — it results in explicit failure.

  • Missing mTLS certificate with RequireMtls = true throws SwishConfigurationException
  • Invalid webhook signature returns HTTP 401 immediately
  • Replay-detected nonce returns HTTP 409
  • Clock skew beyond 5 minutes is rejected by webhook verification

This is intentional engineering discipline. Unsafe states are never silently accepted.