Verification

.NET server SDK

ThirdFactor.SDK — create verification sessions, select workflows, retrieve decisions, and verify signed webhooks from .NET.

The official .NET SDK is a server-only client for the ThirdFactor API. The NuGet package is ThirdFactor.SDK, and its namespace is ThirdFactor.

Warning

Keep your tenant API key on the server. Never put it in browser code, a mobile application, a desktop client, or a public repository.

Requirements

  • .NET 6 or newer; .NET 10 LTS is recommended for new production services
  • No runtime dependencies outside the .NET base class library
  • A tenant API key from Console → Settings → API keys

Installation

dotnet add package ThirdFactor.SDK --version 0.1.0

Create a session and select a workflow

using ThirdFactor;

var thirdFactor = new ThirdFactorClient(
    Environment.GetEnvironmentVariable("THIRDFACTOR_API_KEY")!,
    "https://your-tenant.thirdfactor.ai"
);

using var session = await thirdFactor.CreateSessionAsync(
    new Dictionary<string, object?>
    {
        ["vendor_data"] = "user-42",
        ["workflow_id"] = "4c615aec-e173-450d-8089-30d4edc835f3",
        ["callback_url"] = "https://app.example.com/kyc/done",
        ["contact_email"] = "[email protected]",
        ["metadata"] = new Dictionary<string, object?>
        {
            ["source"] = "dotnet-sdk"
        }
    },
    idempotencyKey: "kyc-user-42"
);

var sessionId = session.RootElement.GetProperty("id").GetString();
var hostedUrl = session.RootElement.GetProperty("url").GetString();

Pass the desired Console workflow UUID as workflow_id. Omit it to use the tenant's default workflow. Persist the session ID and send only the hosted URL to the applicant. Use a stable idempotency key for each logical attempt so a retry returns the original session.

Retrieve a session or decision

using var current = await thirdFactor.RetrieveSessionAsync(sessionId!);
using var decision = await thirdFactor.SessionDecisionAsync(sessionId!);

if (decision.RootElement.GetProperty("decision").GetString() == "approved")
{
    GrantAccess();
}

The hosted UI result is advisory. Grant access, move money, or provision an account only after a signed webhook or this authenticated decision lookup.

Verify webhooks

Pass the untouched HTTP request bytes and the X-Webhook-Signature header before deserializing JSON:

using ThirdFactor;

var secret = Environment.GetEnvironmentVariable("THIRDFACTOR_WEBHOOK_SECRET")!;

using var webhookEvent = ThirdFactorWebhooks.ConstructEvent(
    rawRequestBody,
    signatureHeader,
    secret
);

The verifier uses constant-time HMAC comparison and rejects signatures outside the five-minute replay window by default. ConstructEvent throws an ArgumentException when the signature is invalid, stale, or the body is not valid JSON.

Handle API errors

try
{
    using var decision = await thirdFactor.SessionDecisionAsync(sessionId!);
}
catch (ThirdFactorException error)
{
    Console.Error.WriteLine(error.Status);
    Console.Error.WriteLine(error.ResponseBody);
    Console.Error.WriteLine(error.RequestId);
}

Resources