C#/.NET
VerifySpeed C#/.NET Client Library Documentation
The VerifySpeed .NET client library lets you manage verifications from your backend. It supports message-based methods (WhatsApp Message, Telegram Message), OTP methods (WhatsApp OTP, Telegram OTP, SMS OTP), OTP validation, local token decryption, and API token verification.
Please read Verification Flow and Verification Methods to understand the verification process.
Setup
Step 1: Install the Package
dotnet add package VerifySpeed.VSCSharp
Step 2: Service Registration
Register VerifySpeed in Program.cs or Startup.cs with your server key from the dashboard.
- .NET 6+
- .NET 5
using VSCSharp;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddVerifySpeed("YOUR_SERVER_KEY");
WebApplication app = builder.Build();
app.Run();
using VSCSharp;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddVerifySpeed("YOUR_SERVER_KEY");
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { }
}
Inject IVerifySpeedClient where you need it.
Usage
1. Initializing the Client
Retrieve available verification methods before creating a verification.
using System;
using System.Threading.Tasks;
using VSCSharp.Clients;
using VSCSharp.Exceptions;
using VSCSharp.Models;
public class VerifySpeedExample
{
private readonly IVerifySpeedClient verifySpeedClient;
public VerifySpeedExample(IVerifySpeedClient verifySpeedClient)
{
this.verifySpeedClient = verifySpeedClient;
}
public async Task InitializeVerificationAsync()
{
try
{
InitializeResponse initialization = await verifySpeedClient.InitializeAsync();
Console.WriteLine("Available Verification Methods:");
foreach (Method availableMethod in initialization.AvailableMethods)
{
Console.WriteLine($"- {availableMethod.DisplayName} ({availableMethod.MethodName})");
}
// Return available methods to your client app
}
catch (FailedInitializationException exception)
{
Console.WriteLine($"Initialization failed: {exception.Message}");
}
}
}
2. Creating a Verification
CreateVerificationAsync parameters
| Parameter | Required | Description |
|---|---|---|
methodName | Yes | Verification method identifier (e.g., telegram-message, whatsapp-otp). |
phoneNumber | For OTP methods | User's phone number in E.164 format. Required when methodName is an OTP method (whatsapp-otp, telegram-otp, sms-otp). Omit for message-based methods. |
language | No | Language for the verification flow (e.g., en, ar, ckb). Defaults to en. |
Task<CreatedVerificationResponse> CreateVerificationAsync(
string methodName,
string? phoneNumber = null,
string? language = null
);
Message-based method
For message-based methods (whatsapp-message, telegram-message), omit phoneNumber. The response includes a DeepLink for the client app.
CreatedVerificationResponse createdVerification = await verifySpeedClient.CreateVerificationAsync(
methodName: "telegram-message",
language: "ar"
);
Console.WriteLine($"Verification Key: {createdVerification.VerificationKey}");
Console.WriteLine($"Deep Link: {createdVerification.DeepLink}");
OTP-based method
For OTP methods, pass phoneNumber. VerifySpeed sends the OTP to that number. Your app collects the code and either validates via the client SDK or sends it to your backend for ValidateOtpAsync (see below). See Validating OTP for both approaches.
CreatedVerificationResponse createdVerification = await verifySpeedClient.CreateVerificationAsync(
methodName: "whatsapp-otp",
phoneNumber: "+14255552673",
language: "en"
);
Console.WriteLine($"Verification Key: {createdVerification.VerificationKey}");
// DeepLink is null for OTP methods — return VerificationKey to your client app
3. Validating OTP
Call ValidateOtpAsync from your backend when the user's app sends the OTP code to your server (instead of validating via the Android, iOS, Flutter, or Web client SDK). See Validating OTP.
ValidateOtpAsync parameters
| Parameter | Required | Description |
|---|---|---|
code | Yes | OTP code entered by the user (max 5 characters). |
verificationKey | Yes | VerificationKey from CreateVerificationAsync for the same OTP session. |
/// <summary>
/// Validates an OTP code for a verification session created with an OTP method.
/// </summary>
/// <returns>Check <see cref="ValidateOtpResponse.Succeed"/>; business failures return HTTP 200 with succeed: false.</returns>
/// <exception cref="FailedValidateOtpException">Thrown when the validate-otp HTTP request fails.</exception>
Task<ValidateOtpResponse> ValidateOtpAsync(string code, string verificationKey);
Example
using VSCSharp.Clients;
using VSCSharp.Exceptions;
using VSCSharp.Models;
public async Task ValidateOtpAsync(string code, string verificationKey)
{
try
{
ValidateOtpResponse result = await verifySpeedClient.ValidateOtpAsync(code, verificationKey);
if (result.Succeed)
{
Console.WriteLine($"Phone: {result.PhoneNumber}");
Console.WriteLine($"Token: {result.Token}");
// Optional: decrypt token for methodName, dateOfVerification, verificationKey
DecryptTokenResult decrypted = verifySpeedClient.DecryptToken(result.Token!);
Console.WriteLine($"Method: {decrypted.MethodName}");
Console.WriteLine($"Verified at: {decrypted.DateOfVerification}");
}
else
{
Console.WriteLine($"Error: {result.ErrorMessage} ({result.ErrorCode})");
}
}
catch (FailedValidateOtpException exception)
{
Console.WriteLine($"Request failed: {exception.Message}");
}
}
When Succeed is false, check ErrorCode and ErrorMessage. Known API error codes:
ErrorCode | Description |
|---|---|
OTP_EXPIRED | The OTP session has expired. |
OTP_INVALID | The provided code does not match. |
OTP_ALREADY_VERIFIED | This verification was already completed. |
4. Decrypting Verification Tokens (Local Method)
Recommended approach: Call DecryptToken on your server using the server key configured at registration. No extra VerifySpeed API call. Tokens expire after 5 minutes.
/// <summary>
/// Decrypts the verification token and returns the result.
/// </summary>
DecryptTokenResult DecryptToken(string token);
public void DecryptVerificationToken(string token)
{
try
{
DecryptTokenResult result = verifySpeedClient.DecryptToken(token);
Console.WriteLine($"Phone: {result.PhoneNumber}");
Console.WriteLine($"Method: {result.MethodName}");
Console.WriteLine($"Verification Key: {result.VerificationKey}");
Console.WriteLine($"Verified at: {result.DateOfVerification}");
}
catch (Exception exception)
{
Console.WriteLine($"Token invalid or expired: {exception.Message}");
}
}
Use tokens from ValidateOtpAsync, client SDKs, or message-based verification flows. On ValidateOtpAsync success, PhoneNumber is already in the response; use DecryptToken when you also need MethodName, DateOfVerification, or VerificationKey. See Verification Result Documentation.
5. Verifying a Token via API (Enhanced Security)
The API method returns firstTimeVerified to help detect token reuse—something local decryption alone cannot provide.
Security benefit: VerifyTokenAsync includes FirstTimeVerified, which indicates whether VerifySpeed has seen this token before.
/// <summary>
/// Verifies a verification token via the VerifySpeed API.
/// </summary>
Task<VerifyTokenResponse> VerifyTokenAsync(string token);
public async Task VerifyTokenViaApiAsync(string token)
{
try
{
VerifyTokenResponse result = await verifySpeedClient.VerifyTokenAsync(token);
Console.WriteLine($"Phone: {result.PhoneNumber}");
Console.WriteLine($"Method: {result.MethodName}");
Console.WriteLine($"First time verified: {result.FirstTimeVerified}");
if (result.FirstTimeVerified)
{
// Proceed with business logic
}
else
{
// Handle potential token reuse
}
}
catch (FailedVerifyingTokenException exception)
{
Console.WriteLine($"Token verification failed: {exception.Message}");
}
}
Models
InitializeResponse
Returned by InitializeAsync(). Contains available verification methods.
public record InitializeResponse
{
public List<Method> AvailableMethods { get; init; } = new();
}
public record Method
{
public string MethodName { get; init; } = null!;
public string DisplayName { get; init; } = null!;
}
CreatedVerificationResponse
Returned by CreateVerificationAsync().
public record CreatedVerificationResponse
{
public string MethodName { get; init; } = null!;
public string VerificationKey { get; init; } = null!;
public string? DeepLink { get; init; }
}
DeepLinkis set for message-based methods;nullfor OTP methods.
ValidateOtpResponse
Returned by ValidateOtpAsync().
public record ValidateOtpResponse
{
public bool Succeed { get; init; }
public string? Token { get; init; }
public string? PhoneNumber { get; init; }
public string? ErrorMessage { get; init; }
public string? ErrorCode { get; init; }
}
DecryptTokenResult
Returned by DecryptToken().
public record DecryptTokenResult
{
public string PhoneNumber { get; init; } = null!;
public DateTime DateOfVerification { get; init; }
public string MethodName { get; init; } = null!;
public string VerificationKey { get; init; } = null!;
}
VerifyTokenResponse
Returned by VerifyTokenAsync().
public record VerifyTokenResponse
{
public string MethodName { get; init; } = null!;
public DateTime DateOfVerification { get; init; }
public string PhoneNumber { get; init; } = null!;
public string VerificationKey { get; init; } = null!;
public bool FirstTimeVerified { get; init; }
}
Exceptions
| Exception | When thrown |
|---|---|
FailedInitializationException | Initialization request fails. |
FailedCreateVerificationException | Verification creation fails, or phoneNumber is omitted for an OTP method. |
FailedValidateOtpException | The validate-otp HTTP request fails (network, auth, non-2xx). Business failures such as invalid OTP return HTTP 200 with Succeed: false instead. |
FailedVerifyingTokenException | Token verification via API fails. |
API Example (ASP.NET Core)
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
using VSCSharp.Clients;
using VSCSharp.Exceptions;
using VSCSharp.Models;
[ApiController]
[Route("api/[controller]")]
public class VerificationController : ControllerBase
{
private readonly IVerifySpeedClient verifySpeedClient;
public VerificationController(IVerifySpeedClient verifySpeedClient)
{
this.verifySpeedClient = verifySpeedClient;
}
[HttpPost("initialize")]
public async Task<IActionResult> PostVerificationInitialization()
{
try
{
InitializeResponse initialization = await verifySpeedClient.InitializeAsync();
return Ok(initialization);
}
catch (Exception exception)
{
return BadRequest(exception.Message);
}
}
[HttpPost("create")]
public async Task<IActionResult> PostVerificationCreation([FromBody] PostVerificationCreationRequest request)
{
try
{
CreatedVerificationResponse verification = await verifySpeedClient.CreateVerificationAsync(
methodName: request.MethodType,
phoneNumber: request.PhoneNumber,
language: request.Language
);
return Ok(verification);
}
catch (Exception exception)
{
return BadRequest(exception.Message);
}
}
[HttpPost("validate-otp")]
public async Task<IActionResult> PostValidateOtp([FromBody] PostValidateOtpRequest request)
{
try
{
ValidateOtpResponse result = await verifySpeedClient.ValidateOtpAsync(
request.Code,
request.VerificationKey
);
if (!result.Succeed)
{
return UnprocessableEntity(result);
}
return Ok(result);
}
catch (FailedValidateOtpException exception)
{
return BadRequest(exception.Message);
}
}
[HttpGet("verify/{token}")]
public async Task<IActionResult> GetVerificationResult(string token)
{
try
{
// Option 1: Local decrypt (faster, no reuse detection)
DecryptTokenResult result = verifySpeedClient.DecryptToken(token);
// Option 2: API verification (includes FirstTimeVerified)
// VerifyTokenResponse result = await verifySpeedClient.VerifyTokenAsync(token);
return Ok(result);
}
catch (Exception exception)
{
return BadRequest(exception.Message);
}
}
}
public class PostVerificationCreationRequest
{
[Required]
public string MethodType { get; set; } = string.Empty;
/// <summary>
/// Required for OTP methods (whatsapp-otp, telegram-otp, sms-otp). E.164 format.
/// </summary>
public string? PhoneNumber { get; set; }
public string? Language { get; set; }
}
public class PostValidateOtpRequest
{
[Required]
[MaxLength(5)]
public string Code { get; set; } = string.Empty;
[Required]
public string VerificationKey { get; set; } = string.Empty;
}
License
This package is distributed under the MIT License.