diff --git a/API-reference.md b/API-reference.md
index 18a4f9a..82530f5 100644
--- a/API-reference.md
+++ b/API-reference.md
@@ -1,33 +1,33 @@
## EugeneFox.SimpleOTP package
- **SimpleOTP**
- - [HashAlgorithmProviders](./simpleotp.hashalgorithmproviders.md)
- - [Hotp](./simpleotp.hotp.md)
- - [Otp](./simpleotp.otp.md)
- - [OtpAlgorithm](./simpleotp.otpalgorithm.md)
- - [OtpCode](./simpleotp.otpcode.md)
- - [OtpConfig](./simpleotp.otpconfig.md)
- - [OtpSecret](./simpleotp.otpsecret.md)
- - [OtpType](./simpleotp.otptype.md)
- - [OtpUriFormat](./simpleotp.otpuriformat.md)
- - [ToleranceSpan](./simpleotp.tolerancespan.md)
- - [Totp](./simpleotp.totp.md)
+ - [HashAlgorithmProviders](./simpleotp.hashalgorithmproviders)
+ - [Hotp](./simpleotp.hotp)
+ - [Otp](./simpleotp.otp)
+ - [OtpAlgorithm](./simpleotp.otpalgorithm)
+ - [OtpCode](./simpleotp.otpcode)
+ - [OtpConfig](./simpleotp.otpconfig)
+ - [OtpSecret](./simpleotp.otpsecret)
+ - [OtpType](./simpleotp.otptype)
+ - [OtpUriFormat](./simpleotp.otpuriformat)
+ - [ToleranceSpan](./simpleotp.tolerancespan)
+ - [Totp](./simpleotp.totp)
- **SimpleOTP.Converters**
- - [OtpAlgorithmJsonConverter](./simpleotp.converters.otpalgorithmjsonconverter.md)
- - [OtpCodeJsonConverter](./simpleotp.converters.otpcodejsonconverter.md)
- - [OtpConfigJsonConverter](./simpleotp.converters.otpconfigjsonconverter.md)
- - [OtpSecretJsonConverter](./simpleotp.converters.otpsecretjsonconverter.md)
+ - [OtpAlgorithmJsonConverter](./simpleotp.converters.otpalgorithmjsonconverter)
+ - [OtpCodeJsonConverter](./simpleotp.converters.otpcodejsonconverter)
+ - [OtpConfigJsonConverter](./simpleotp.converters.otpconfigjsonconverter)
+ - [OtpSecretJsonConverter](./simpleotp.converters.otpsecretjsonconverter)
- **SimpleOTP.Encoding**
- - [Base32Encoder](./simpleotp.encoding.base32encoder.md)
- - [IEncoder](./simpleotp.encoding.iencoder.md)
+ - [Base32Encoder](./simpleotp.encoding.base32encoder)
+ - [IEncoder](./simpleotp.encoding.iencoder)
- **SimpleOTP.Fluent**
- - [OtpBuilder](./simpleotp.fluent.otpbuilder.md)
- - [OtpConfigBuilder](./simpleotp.fluent.otpconfigbuilder.md)
- - [OtpConfigFluentExtensions](./simpleotp.fluent.otpconfigfluentextensions.md)
- - [OtpFluentExtensions](./simpleotp.fluent.otpfluentextensions.md)
+ - [OtpBuilder](./simpleotp.fluent.otpbuilder)
+ - [OtpConfigBuilder](./simpleotp.fluent.otpconfigbuilder)
+ - [OtpConfigFluentExtensions](./simpleotp.fluent.otpconfigfluentextensions)
+ - [OtpFluentExtensions](./simpleotp.fluent.otpfluentextensions)
## EugeneFox.SimpleOTP.DependencyInjection package
diff --git a/HashAlgorithmProviders.md b/HashAlgorithmProviders.md
deleted file mode 100644
index 9b8b198..0000000
--- a/HashAlgorithmProviders.md
+++ /dev/null
@@ -1,89 +0,0 @@
-Namespace: SimpleOTP
-
-Provides methods for registering and retrieving providers.
-
-```csharp
-public static class HashAlgorithmProviders
-```
-
-Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [HashAlgorithmProviders](./simpleotp.hashalgorithmproviders.md)
-Attributes [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute)
-
-## Methods
-
-### **AddProvider(OtpAlgorithm, KeyedHashAlgorithm)**
-
-Registers a new provider.
-
-```csharp
-public static void AddProvider(OtpAlgorithm algorithm, KeyedHashAlgorithm algorithmProvider)
-```
-
-#### Parameters
-
-`algorithm` [OtpAlgorithm](./simpleotp.otpalgorithm.md)
-The algorithm to register.
-
-`algorithmProvider` KeyedHashAlgorithm
-The provider to register.
-
-### **GetProvider(OtpAlgorithm)**
-
-Retrieves a provider.
-
-```csharp
-public static KeyedHashAlgorithm GetProvider(OtpAlgorithm algorithm)
-```
-
-#### Parameters
-
-`algorithm` [OtpAlgorithm](./simpleotp.otpalgorithm.md)
-The algorithm to retrieve.
-
-#### Returns
-
-KeyedHashAlgorithm
-The provider, or `null` if not found.
-
-### **RemoveProvider(OtpAlgorithm)**
-
-Removes a provider.
-
-```csharp
-public static void RemoveProvider(OtpAlgorithm algorithm)
-```
-
-#### Parameters
-
-`algorithm` [OtpAlgorithm](./simpleotp.otpalgorithm.md)
-The algorithm to remove.
-
-### **IsRegistered(OtpAlgorithm)**
-
-Determines whether a provider is registered.
-
-```csharp
-public static bool IsRegistered(OtpAlgorithm algorithm)
-```
-
-#### Parameters
-
-`algorithm` [OtpAlgorithm](./simpleotp.otpalgorithm.md)
-The algorithm to check.
-
-#### Returns
-
-[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
-`true` if the provider is registered; otherwise, `false`.
-
-### **ClearProviders()**
-
-Removes all registered providers.
-
-```csharp
-public static void ClearProviders()
-```
-
-**Remarks:**
-
-This method also clears default providers. Use with caution.
diff --git a/index.md b/index.md
new file mode 100644
index 0000000..41f30e4
--- /dev/null
+++ b/index.md
@@ -0,0 +1,51 @@
+# SimpleOTP
+
+## SimpleOTP
+
+[HashAlgorithmProviders](./simpleotp.hashalgorithmproviders)
+
+[Hotp](./simpleotp.hotp)
+
+[Otp](./simpleotp.otp)
+
+[OtpAlgorithm](./simpleotp.otpalgorithm)
+
+[OtpCode](./simpleotp.otpcode)
+
+[OtpConfig](./simpleotp.otpconfig)
+
+[OtpSecret](./simpleotp.otpsecret)
+
+[OtpType](./simpleotp.otptype)
+
+[OtpUriFormat](./simpleotp.otpuriformat)
+
+[ToleranceSpan](./simpleotp.tolerancespan)
+
+[Totp](./simpleotp.totp)
+
+## SimpleOTP.Converters
+
+[OtpAlgorithmJsonConverter](./simpleotp.converters.otpalgorithmjsonconverter)
+
+[OtpCodeJsonConverter](./simpleotp.converters.otpcodejsonconverter)
+
+[OtpConfigJsonConverter](./simpleotp.converters.otpconfigjsonconverter)
+
+[OtpSecretJsonConverter](./simpleotp.converters.otpsecretjsonconverter)
+
+## SimpleOTP.Encoding
+
+[Base32Encoder](./simpleotp.encoding.base32encoder)
+
+[IEncoder](./simpleotp.encoding.iencoder)
+
+## SimpleOTP.Fluent
+
+[OtpBuilder](./simpleotp.fluent.otpbuilder)
+
+[OtpConfigBuilder](./simpleotp.fluent.otpconfigbuilder)
+
+[OtpConfigFluentExtensions](./simpleotp.fluent.otpconfigfluentextensions)
+
+[OtpFluentExtensions](./simpleotp.fluent.otpfluentextensions)
diff --git a/simpleotp.converters.otpalgorithmjsonconverter.md b/simpleotp.converters.otpalgorithmjsonconverter.md
new file mode 100644
index 0000000..2458f3a
--- /dev/null
+++ b/simpleotp.converters.otpalgorithmjsonconverter.md
@@ -0,0 +1,76 @@
+# OtpAlgorithmJsonConverter
+
+Namespace: SimpleOTP.Converters
+
+Provides a JSON converter for [OtpAlgorithm](simpleotp.otpalgorithm).
+
+```csharp
+public class OtpAlgorithmJsonConverter : System.Text.Json.Serialization.JsonConverter`1[[SimpleOTP.OtpAlgorithm, SimpleOTP, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]]
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → JsonConverter → JsonConverter<OtpAlgorithm> → [OtpAlgorithmJsonConverter](simpleotp.converters.otpalgorithmjsonconverter)
+Attributes [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute)
+
+## Properties
+
+### **HandleNull**
+
+```csharp
+public bool HandleNull { get; }
+```
+
+#### Property Value
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **Type**
+
+```csharp
+public Type Type { get; }
+```
+
+#### Property Value
+
+[Type](https://docs.microsoft.com/en-us/dotnet/api/system.type)
+
+## Constructors
+
+### **OtpAlgorithmJsonConverter()**
+
+```csharp
+public OtpAlgorithmJsonConverter()
+```
+
+## Methods
+
+### **Read(Utf8JsonReader&, Type, JsonSerializerOptions)**
+
+```csharp
+public OtpAlgorithm Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
+```
+
+#### Parameters
+
+`reader` Utf8JsonReader&
+
+`typeToConvert` [Type](https://docs.microsoft.com/en-us/dotnet/api/system.type)
+
+`options` JsonSerializerOptions
+
+#### Returns
+
+[OtpAlgorithm](simpleotp.otpalgorithm)
+
+### **Write(Utf8JsonWriter, OtpAlgorithm, JsonSerializerOptions)**
+
+```csharp
+public void Write(Utf8JsonWriter writer, OtpAlgorithm value, JsonSerializerOptions options)
+```
+
+#### Parameters
+
+`writer` Utf8JsonWriter
+
+`value` [OtpAlgorithm](simpleotp.otpalgorithm)
+
+`options` JsonSerializerOptions
diff --git a/simpleotp.converters.otpcodejsonconverter.md b/simpleotp.converters.otpcodejsonconverter.md
new file mode 100644
index 0000000..94f1471
--- /dev/null
+++ b/simpleotp.converters.otpcodejsonconverter.md
@@ -0,0 +1,76 @@
+# OtpCodeJsonConverter
+
+Namespace: SimpleOTP.Converters
+
+Provides a JSON converter for [OtpCode](simpleotp.otpcode).
+
+```csharp
+public class OtpCodeJsonConverter : System.Text.Json.Serialization.JsonConverter`1[[SimpleOTP.OtpCode, SimpleOTP, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]]
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → JsonConverter → JsonConverter<OtpCode> → [OtpCodeJsonConverter](simpleotp.converters.otpcodejsonconverter)
+Attributes [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute)
+
+## Properties
+
+### **HandleNull**
+
+```csharp
+public bool HandleNull { get; }
+```
+
+#### Property Value
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **Type**
+
+```csharp
+public Type Type { get; }
+```
+
+#### Property Value
+
+[Type](https://docs.microsoft.com/en-us/dotnet/api/system.type)
+
+## Constructors
+
+### **OtpCodeJsonConverter()**
+
+```csharp
+public OtpCodeJsonConverter()
+```
+
+## Methods
+
+### **Read(Utf8JsonReader&, Type, JsonSerializerOptions)**
+
+```csharp
+public OtpCode Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
+```
+
+#### Parameters
+
+`reader` Utf8JsonReader&
+
+`typeToConvert` [Type](https://docs.microsoft.com/en-us/dotnet/api/system.type)
+
+`options` JsonSerializerOptions
+
+#### Returns
+
+[OtpCode](simpleotp.otpcode)
+
+### **Write(Utf8JsonWriter, OtpCode, JsonSerializerOptions)**
+
+```csharp
+public void Write(Utf8JsonWriter writer, OtpCode value, JsonSerializerOptions options)
+```
+
+#### Parameters
+
+`writer` Utf8JsonWriter
+
+`value` [OtpCode](simpleotp.otpcode)
+
+`options` JsonSerializerOptions
diff --git a/simpleotp.converters.otpconfigjsonconverter.md b/simpleotp.converters.otpconfigjsonconverter.md
new file mode 100644
index 0000000..094bb17
--- /dev/null
+++ b/simpleotp.converters.otpconfigjsonconverter.md
@@ -0,0 +1,76 @@
+# OtpConfigJsonConverter
+
+Namespace: SimpleOTP.Converters
+
+Provides a JSON converter for [OtpConfig](simpleotp.otpconfig).
+
+```csharp
+public class OtpConfigJsonConverter : System.Text.Json.Serialization.JsonConverter`1[[SimpleOTP.OtpConfig, SimpleOTP, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]]
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → JsonConverter → JsonConverter<OtpConfig> → [OtpConfigJsonConverter](simpleotp.converters.otpconfigjsonconverter)
+Attributes [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute)
+
+## Properties
+
+### **HandleNull**
+
+```csharp
+public bool HandleNull { get; }
+```
+
+#### Property Value
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **Type**
+
+```csharp
+public Type Type { get; }
+```
+
+#### Property Value
+
+[Type](https://docs.microsoft.com/en-us/dotnet/api/system.type)
+
+## Constructors
+
+### **OtpConfigJsonConverter()**
+
+```csharp
+public OtpConfigJsonConverter()
+```
+
+## Methods
+
+### **Read(Utf8JsonReader&, Type, JsonSerializerOptions)**
+
+```csharp
+public OtpConfig Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
+```
+
+#### Parameters
+
+`reader` Utf8JsonReader&
+
+`typeToConvert` [Type](https://docs.microsoft.com/en-us/dotnet/api/system.type)
+
+`options` JsonSerializerOptions
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+
+### **Write(Utf8JsonWriter, OtpConfig, JsonSerializerOptions)**
+
+```csharp
+public void Write(Utf8JsonWriter writer, OtpConfig value, JsonSerializerOptions options)
+```
+
+#### Parameters
+
+`writer` Utf8JsonWriter
+
+`value` [OtpConfig](simpleotp.otpconfig)
+
+`options` JsonSerializerOptions
diff --git a/simpleotp.converters.otpsecretjsonconverter.md b/simpleotp.converters.otpsecretjsonconverter.md
new file mode 100644
index 0000000..b1af5f2
--- /dev/null
+++ b/simpleotp.converters.otpsecretjsonconverter.md
@@ -0,0 +1,76 @@
+# OtpSecretJsonConverter
+
+Namespace: SimpleOTP.Converters
+
+Provides a JSON converter for [OtpSecret](simpleotp.otpsecret).
+
+```csharp
+public class OtpSecretJsonConverter : System.Text.Json.Serialization.JsonConverter`1[[SimpleOTP.OtpSecret, SimpleOTP, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]]
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → JsonConverter → JsonConverter<OtpSecret> → [OtpSecretJsonConverter](simpleotp.converters.otpsecretjsonconverter)
+Attributes [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute)
+
+## Properties
+
+### **HandleNull**
+
+```csharp
+public bool HandleNull { get; }
+```
+
+#### Property Value
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **Type**
+
+```csharp
+public Type Type { get; }
+```
+
+#### Property Value
+
+[Type](https://docs.microsoft.com/en-us/dotnet/api/system.type)
+
+## Constructors
+
+### **OtpSecretJsonConverter()**
+
+```csharp
+public OtpSecretJsonConverter()
+```
+
+## Methods
+
+### **Read(Utf8JsonReader&, Type, JsonSerializerOptions)**
+
+```csharp
+public OtpSecret Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
+```
+
+#### Parameters
+
+`reader` Utf8JsonReader&
+
+`typeToConvert` [Type](https://docs.microsoft.com/en-us/dotnet/api/system.type)
+
+`options` JsonSerializerOptions
+
+#### Returns
+
+[OtpSecret](simpleotp.otpsecret)
+
+### **Write(Utf8JsonWriter, OtpSecret, JsonSerializerOptions)**
+
+```csharp
+public void Write(Utf8JsonWriter writer, OtpSecret value, JsonSerializerOptions options)
+```
+
+#### Parameters
+
+`writer` Utf8JsonWriter
+
+`value` [OtpSecret](simpleotp.otpsecret)
+
+`options` JsonSerializerOptions
diff --git a/simpleotp.encoding.base32encoder.md b/simpleotp.encoding.base32encoder.md
new file mode 100644
index 0000000..d41bde0
--- /dev/null
+++ b/simpleotp.encoding.base32encoder.md
@@ -0,0 +1,146 @@
+# Base32Encoder
+
+Namespace: SimpleOTP.Encoding
+
+Provides methods for encoding and decoding data using the RFC 4648 Base32 standard alphabet.
+
+```csharp
+public class Base32Encoder : IEncoder
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [Base32Encoder](simpleotp.encoding.base32encoder)
+Implements [IEncoder](simpleotp.encoding.iencoder)
+Attributes [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute)
+
+## Properties
+
+### **Instance**
+
+Gets the singleton instance of the [Base32Encoder](simpleotp.encoding.base32encoder) class.
+
+```csharp
+public static Base32Encoder Instance { get; }
+```
+
+#### Property Value
+
+[Base32Encoder](simpleotp.encoding.base32encoder)
+
+### **Scheme**
+
+```csharp
+public string Scheme { get; }
+```
+
+#### Property Value
+
+[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+
+## Constructors
+
+### **Base32Encoder()**
+
+```csharp
+public Base32Encoder()
+```
+
+## Methods
+
+### **EncodeBytes(Byte[])**
+
+Converts a byte array to a Base32 string representation.
+
+```csharp
+public string EncodeBytes(Byte[] bytes)
+```
+
+#### Parameters
+
+`bytes` [Byte[]](https://docs.microsoft.com/en-us/dotnet/api/system.byte)
+The byte array to convert.
+
+#### Returns
+
+[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The Base32 string representation of the byte array.
+
+#### Exceptions
+
+[ArgumentNullException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception)
+Thrown when parameter is null.
+
+### **GetBytes(String)**
+
+Converts a Base32 encoded string to a byte array.
+
+```csharp
+public Byte[] GetBytes(string inArray)
+```
+
+#### Parameters
+
+`inArray` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The Base32 encoded string to convert.
+
+#### Returns
+
+[Byte[]](https://docs.microsoft.com/en-us/dotnet/api/system.byte)
+The byte array representation of the Base32 encoded string.
+
+#### Exceptions
+
+[ArgumentNullException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception)
+Thrown when parameter is null.
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+Thrown when `inArray` is empty, whitespace, or contains invalid characters.
+
+**Remarks:**
+
+Trailing bits are ignored (e.g. AAAR will be treated as AAAQ - 0x00 0x01).
+
+### **CharToValue(Char)**
+
+Converts a Base32 character to its numeric value.
+
+```csharp
+protected int CharToValue(char c)
+```
+
+#### Parameters
+
+`c` [Char](https://docs.microsoft.com/en-us/dotnet/api/system.char)
+The Base32 character to convert.
+
+#### Returns
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The numeric value of the Base32 character.
+
+#### Exceptions
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+Thrown when `c` is not a valid Base32 character.
+
+### **ValueToChar(Int32)**
+
+Converts a numeric value to its Base32 character.
+
+```csharp
+protected char ValueToChar(int value)
+```
+
+#### Parameters
+
+`value` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The numeric value to convert.
+
+#### Returns
+
+[Char](https://docs.microsoft.com/en-us/dotnet/api/system.char)
+The Base32 character corresponding to the numeric value.
+
+#### Exceptions
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+Thrown when `value` is not a valid Base32 value.
diff --git a/simpleotp.encoding.iencoder.md b/simpleotp.encoding.iencoder.md
new file mode 100644
index 0000000..ff1fab5
--- /dev/null
+++ b/simpleotp.encoding.iencoder.md
@@ -0,0 +1,63 @@
+# IEncoder
+
+Namespace: SimpleOTP.Encoding
+
+Provides methods for encoding and decoding data using the RFC 4648 Base32 "Extended Hex" alphabet.
+
+```csharp
+public interface IEncoder
+```
+
+Attributes [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute)
+
+## Properties
+
+### **Scheme**
+
+Gets the encoding scheme used by the encoder (e.g. `base32` or `base32hex`).
+
+```csharp
+public abstract string Scheme { get; }
+```
+
+#### Property Value
+
+[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+
+## Methods
+
+### **EncodeBytes(Byte[])**
+
+Converts a byte array to a Base32 string representation.
+
+```csharp
+string EncodeBytes(Byte[] data)
+```
+
+#### Parameters
+
+`data` [Byte[]](https://docs.microsoft.com/en-us/dotnet/api/system.byte)
+The byte array to convert.
+
+#### Returns
+
+[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The Base32 string representation of the byte array.
+
+### **GetBytes(String)**
+
+Converts a Base32 encoded string to a byte array.
+
+```csharp
+Byte[] GetBytes(string data)
+```
+
+#### Parameters
+
+`data` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The Base32 encoded string to convert.
+
+#### Returns
+
+[Byte[]](https://docs.microsoft.com/en-us/dotnet/api/system.byte)
+The byte array representation of the Base32 encoded string.
diff --git a/simpleotp.fluent.otpbuilder.md b/simpleotp.fluent.otpbuilder.md
new file mode 100644
index 0000000..5c14122
--- /dev/null
+++ b/simpleotp.fluent.otpbuilder.md
@@ -0,0 +1,68 @@
+# OtpBuilder
+
+Namespace: SimpleOTP.Fluent
+
+Class used to streamline OTP code generation on client devices.
+
+```csharp
+public static class OtpBuilder
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [OtpBuilder](simpleotp.fluent.otpbuilder)
+Attributes [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute)
+
+## Methods
+
+### **UseTotp(Int32)**
+
+Use TOTP generator with optional counter period.
+
+```csharp
+public static Otp UseTotp(int period)
+```
+
+#### Parameters
+
+`period` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+Period in seconds.
+
+#### Returns
+
+[Otp](simpleotp.otp)
+[Otp](simpleotp.otp) instance.
+
+### **UseHotp(Int64)**
+
+Use HOTP generator with optional counter value.
+
+```csharp
+public static Otp UseHotp(long counter)
+```
+
+#### Parameters
+
+`counter` [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+Counter value.
+
+#### Returns
+
+[Otp](simpleotp.otp)
+[Otp](simpleotp.otp) instance.
+
+### **FromConfig(OtpConfig)**
+
+Creates [Otp](simpleotp.otp) instance from [OtpConfig](simpleotp.otpconfig) object.
+
+```csharp
+public static Otp FromConfig(OtpConfig config)
+```
+
+#### Parameters
+
+`config` [OtpConfig](simpleotp.otpconfig)
+[OtpConfig](simpleotp.otpconfig) object.
+
+#### Returns
+
+[Otp](simpleotp.otp)
+[Otp](simpleotp.otp) instance.
diff --git a/simpleotp.fluent.otpconfigbuilder.md b/simpleotp.fluent.otpconfigbuilder.md
new file mode 100644
index 0000000..c93e5d5
--- /dev/null
+++ b/simpleotp.fluent.otpconfigbuilder.md
@@ -0,0 +1,80 @@
+# OtpConfigBuilder
+
+Namespace: SimpleOTP.Fluent
+
+Class used to streamline OTP code configuration on client devices.
+
+```csharp
+public static class OtpConfigBuilder
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [OtpConfigBuilder](simpleotp.fluent.otpconfigbuilder)
+Attributes [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute)
+
+## Methods
+
+### **UseTotp(String, Int32)**
+
+Use TOTP configuration with optional counter period.
+
+```csharp
+public static OtpConfig UseTotp(string accountName, int period)
+```
+
+#### Parameters
+
+`accountName` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+Account name.
+
+`period` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+Period in seconds.
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+[OtpConfig](simpleotp.otpconfig) instance.
+
+### **UseHotp(String, Int64)**
+
+Use HOTP configuration with optional counter.
+
+```csharp
+public static OtpConfig UseHotp(string accountName, long counter)
+```
+
+#### Parameters
+
+`accountName` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+Account name.
+
+`counter` [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+Counter value.
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+[OtpConfig](simpleotp.otpconfig) instance.
+
+### **UseApple(String, String, String)**
+
+Use TOTP which satisfies Apple's specification requirements.
+
+```csharp
+public static OtpConfig UseApple(string accountName, string issuerName, string issuerDomain)
+```
+
+#### Parameters
+
+`accountName` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+Account name.
+
+`issuerName` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+Issuer/application/service display name.
+
+`issuerDomain` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+Issuer/application/service domain name.
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+[OtpConfig](simpleotp.otpconfig) instance.
diff --git a/simpleotp.fluent.otpconfigfluentextensions.md b/simpleotp.fluent.otpconfigfluentextensions.md
new file mode 100644
index 0000000..832dadc
--- /dev/null
+++ b/simpleotp.fluent.otpconfigfluentextensions.md
@@ -0,0 +1,219 @@
+# OtpConfigFluentExtensions
+
+Namespace: SimpleOTP.Fluent
+
+Provides fluent API for configuring [OtpConfig](simpleotp.otpconfig) objects.
+
+```csharp
+public static class OtpConfigFluentExtensions
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [OtpConfigFluentExtensions](simpleotp.fluent.otpconfigfluentextensions)
+Attributes [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute), [ExtensionAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.extensionattribute)
+
+## Methods
+
+### **WithLabel(OtpConfig, String)**
+
+Sets the [OtpConfig.Label](simpleotp.otpconfig#label) property.
+
+```csharp
+public static OtpConfig WithLabel(OtpConfig config, string label)
+```
+
+#### Parameters
+
+`config` [OtpConfig](simpleotp.otpconfig)
+The [OtpConfig](simpleotp.otpconfig) object to configure.
+
+`label` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The label of the OTP config.
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+The configured [OtpConfig](simpleotp.otpconfig) object.
+
+### **WithIssuer(OtpConfig, String)**
+
+Sets the [OtpConfig.Issuer](simpleotp.otpconfig#issuer) property.
+
+```csharp
+public static OtpConfig WithIssuer(OtpConfig config, string issuer)
+```
+
+#### Parameters
+
+`config` [OtpConfig](simpleotp.otpconfig)
+The [OtpConfig](simpleotp.otpconfig) object to configure.
+
+`issuer` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The issuer of the OTP config.
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+The configured [OtpConfig](simpleotp.otpconfig) object.
+
+### **WithAppleIssuer(OtpConfig, String, String)**
+
+Sets the issuer info, according to Apple specification.
+
+```csharp
+public static OtpConfig WithAppleIssuer(OtpConfig config, string displayName, string domain)
+```
+
+#### Parameters
+
+`config` [OtpConfig](simpleotp.otpconfig)
+The [OtpConfig](simpleotp.otpconfig) object to configure.
+
+`displayName` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The display name of the issuer.
+
+`domain` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The domain name of the issuer.
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+
+### **WithNewSecret(OtpConfig, Int32)**
+
+Sets the [OtpConfig.Secret](simpleotp.otpconfig#secret) property with a new secret.
+
+```csharp
+public static OtpConfig WithNewSecret(OtpConfig config, int bytesLength)
+```
+
+#### Parameters
+
+`config` [OtpConfig](simpleotp.otpconfig)
+The [OtpConfig](simpleotp.otpconfig) object to configure.
+
+`bytesLength` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The length of the secret in bytes.
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+The configured [OtpConfig](simpleotp.otpconfig) object.
+
+### **WithSecret(OtpConfig, OtpSecret)**
+
+Sets the [OtpConfig.Secret](simpleotp.otpconfig#secret) property with specified secret.
+
+```csharp
+public static OtpConfig WithSecret(OtpConfig config, OtpSecret secret)
+```
+
+#### Parameters
+
+`config` [OtpConfig](simpleotp.otpconfig)
+The [OtpConfig](simpleotp.otpconfig) object to configure.
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret to use.
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+The configured [OtpConfig](simpleotp.otpconfig) object.
+
+### **WithAlgorithm(OtpConfig, OtpAlgorithm)**
+
+Sets the [OtpConfig.Algorithm](simpleotp.otpconfig#algorithm) property.
+
+```csharp
+public static OtpConfig WithAlgorithm(OtpConfig config, OtpAlgorithm algorithm)
+```
+
+#### Parameters
+
+`config` [OtpConfig](simpleotp.otpconfig)
+The [OtpConfig](simpleotp.otpconfig) object to configure.
+
+`algorithm` [OtpAlgorithm](simpleotp.otpalgorithm)
+The algorithm to use.
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+The configured [OtpConfig](simpleotp.otpconfig) object.
+
+**Remarks:**
+
+Not recommended for use, since most implementations do not support custom values.
+
+### **WithDigits(OtpConfig, Int32)**
+
+Sets the [OtpConfig.Digits](simpleotp.otpconfig#digits) property.
+
+```csharp
+public static OtpConfig WithDigits(OtpConfig config, int digits)
+```
+
+#### Parameters
+
+`config` [OtpConfig](simpleotp.otpconfig)
+The [OtpConfig](simpleotp.otpconfig) object to configure.
+
+`digits` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The number of digits to use.
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+The configured [OtpConfig](simpleotp.otpconfig) object.
+
+**Remarks:**
+
+Not recommended for use, since most implementations do not support custom values.
+
+### **AddCustomProperty(OtpConfig, String, String)**
+
+Adds a custom vendor-specific property to the [OtpConfig](simpleotp.otpconfig).
+
+```csharp
+public static OtpConfig AddCustomProperty(OtpConfig config, string key, string value)
+```
+
+#### Parameters
+
+`config` [OtpConfig](simpleotp.otpconfig)
+The [OtpConfig](simpleotp.otpconfig) object to configure.
+
+`key` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The key of the property.
+
+`value` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The value of the property.
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+The configured [OtpConfig](simpleotp.otpconfig) object.
+
+**Remarks:**
+
+If set, reserved keys
+ `issuer, digits, counter, secret, period and algorithm`
+ will be removed from the [OtpConfig.CustomProperties](simpleotp.otpconfig#customproperties) upon it's serialization to URI.
+
+### **CreateGenerator(OtpConfig)**
+
+Creates a new [Otp](simpleotp.otp) object from the provided [OtpConfig](simpleotp.otpconfig)
+
+```csharp
+public static Otp CreateGenerator(OtpConfig config)
+```
+
+#### Parameters
+
+`config` [OtpConfig](simpleotp.otpconfig)
+The [OtpConfig](simpleotp.otpconfig) object to use.
+
+#### Returns
+
+[Otp](simpleotp.otp)
+A new [Otp](simpleotp.otp) object.
diff --git a/simpleotp.fluent.otpfluentextensions.md b/simpleotp.fluent.otpfluentextensions.md
new file mode 100644
index 0000000..8ce710b
--- /dev/null
+++ b/simpleotp.fluent.otpfluentextensions.md
@@ -0,0 +1,98 @@
+# OtpFluentExtensions
+
+Namespace: SimpleOTP.Fluent
+
+Provides fluent API for configuring [Otp](simpleotp.otp) objects.
+
+```csharp
+public static class OtpFluentExtensions
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [OtpFluentExtensions](simpleotp.fluent.otpfluentextensions)
+Attributes [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute), [ExtensionAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.extensionattribute)
+
+## Methods
+
+### **WithNewSecret(Otp, Int32)**
+
+Creates a new [Otp](simpleotp.otp) object from the provided [OtpConfig](simpleotp.otpconfig)
+
+```csharp
+public static Otp WithNewSecret(Otp generator, int bytesLength)
+```
+
+#### Parameters
+
+`generator` [Otp](simpleotp.otp)
+The [Otp](simpleotp.otp) object to configure.
+
+`bytesLength` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The length of the secret in bytes.
+
+#### Returns
+
+[Otp](simpleotp.otp)
+The configured [Otp](simpleotp.otp) object.
+
+### **WithSecret(Otp, OtpSecret)**
+
+Creates a new [Otp](simpleotp.otp) object from the provided [OtpSecret](simpleotp.otpsecret)
+
+```csharp
+public static Otp WithSecret(Otp generator, OtpSecret secret)
+```
+
+#### Parameters
+
+`generator` [Otp](simpleotp.otp)
+The [Otp](simpleotp.otp) object to configure.
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The [OtpSecret](simpleotp.otpsecret) to use.
+
+#### Returns
+
+[Otp](simpleotp.otp)
+The configured [Otp](simpleotp.otp) object.
+
+### **WithDigits(Otp, Int32)**
+
+Sets the [Otp.Digits](simpleotp.otp#digits) property.
+
+```csharp
+public static Otp WithDigits(Otp generator, int digits)
+```
+
+#### Parameters
+
+`generator` [Otp](simpleotp.otp)
+The [Otp](simpleotp.otp) object to configure.
+
+`digits` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The number of digits to use in OTP codes.
+
+#### Returns
+
+[Otp](simpleotp.otp)
+The configured [Otp](simpleotp.otp) object.
+
+### **WithAlgorithm(Otp, OtpAlgorithm)**
+
+Sets the [Otp.Algorithm](simpleotp.otp#algorithm) property.
+
+```csharp
+public static Otp WithAlgorithm(Otp generator, OtpAlgorithm algorithm)
+```
+
+#### Parameters
+
+`generator` [Otp](simpleotp.otp)
+The [Otp](simpleotp.otp) object to configure.
+
+`algorithm` [OtpAlgorithm](simpleotp.otpalgorithm)
+The algorithm to use.
+
+#### Returns
+
+[Otp](simpleotp.otp)
+The configured [Otp](simpleotp.otp) object.
diff --git a/simpleotp.hotp.md b/simpleotp.hotp.md
new file mode 100644
index 0000000..ecc6606
--- /dev/null
+++ b/simpleotp.hotp.md
@@ -0,0 +1,169 @@
+# Hotp
+
+Namespace: SimpleOTP
+
+Represents a HOTP (HMAC-based One-Time Password) generator.
+
+```csharp
+public class Hotp : Otp
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [Otp](simpleotp.otp) → [Hotp](simpleotp.hotp)
+Attributes [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute)
+
+## Properties
+
+### **Counter**
+
+Gets or sets the counter value used for generating OTP codes.
+
+```csharp
+public long Counter { get; set; }
+```
+
+#### Property Value
+
+[Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+
+### **Secret**
+
+Gets or sets the secret key used for generating OTPs.
+
+```csharp
+public OtpSecret Secret { get; set; }
+```
+
+#### Property Value
+
+[OtpSecret](simpleotp.otpsecret)
+
+### **Algorithm**
+
+Gets or sets the algorithm used for generating OTP codes.
+
+```csharp
+public OtpAlgorithm Algorithm { get; set; }
+```
+
+#### Property Value
+
+[OtpAlgorithm](simpleotp.otpalgorithm)
+
+### **Digits**
+
+Gets or sets the number of digits in the OTP code.
+
+```csharp
+public int Digits { get; set; }
+```
+
+#### Property Value
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+Default: 6. Recommended: 6-8.
+
+## Constructors
+
+### **Hotp(OtpSecret)**
+
+Initializes a new instance of the [Hotp](simpleotp.hotp) class
+
+```csharp
+public Hotp(OtpSecret secret)
+```
+
+#### Parameters
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret key used for generating OTP codes.
+
+### **Hotp(OtpSecret, Int64)**
+
+Initializes a new instance of the [Hotp](simpleotp.hotp) class
+
+```csharp
+public Hotp(OtpSecret secret, long counter)
+```
+
+#### Parameters
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret key used for generating OTP codes.
+
+`counter` [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+The counter value used for generating OTP codes.
+
+### **Hotp(OtpSecret, Int64, Int32)**
+
+Initializes a new instance of the [Hotp](simpleotp.hotp) class
+
+```csharp
+public Hotp(OtpSecret secret, long counter, int digits)
+```
+
+#### Parameters
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret key used for generating OTP codes.
+
+`counter` [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+The counter value used for generating OTP codes.
+
+`digits` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The number of digits in the OTP code.
+
+### **Hotp(OtpSecret, Int64, OtpAlgorithm)**
+
+Initializes a new instance of the [Hotp](simpleotp.hotp) class
+
+```csharp
+public Hotp(OtpSecret secret, long counter, OtpAlgorithm algorithm)
+```
+
+#### Parameters
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret key used for generating OTP codes.
+
+`counter` [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+The counter value used for generating OTP codes.
+
+`algorithm` [OtpAlgorithm](simpleotp.otpalgorithm)
+The algorithm used for generating OTP codes.
+
+### **Hotp(OtpSecret, Int64, OtpAlgorithm, Int32)**
+
+Initializes a new instance of the [Hotp](simpleotp.hotp) class
+
+```csharp
+public Hotp(OtpSecret secret, long counter, OtpAlgorithm algorithm, int digits)
+```
+
+#### Parameters
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret key used for generating OTP codes.
+
+`counter` [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+The counter value used for generating OTP codes.
+
+`algorithm` [OtpAlgorithm](simpleotp.otpalgorithm)
+The algorithm used for generating OTP codes.
+
+`digits` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The number of digits in the OTP code.
+
+## Methods
+
+### **GetCounter()**
+
+Gets the current counter value.
+
+```csharp
+protected long GetCounter()
+```
+
+#### Returns
+
+[Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+The current counter value.
diff --git a/simpleotp.otp.md b/simpleotp.otp.md
new file mode 100644
index 0000000..673df30
--- /dev/null
+++ b/simpleotp.otp.md
@@ -0,0 +1,326 @@
+# Otp
+
+Namespace: SimpleOTP
+
+Represents an abstract class for generating and validating One-Time Passwords (OTP).
+
+```csharp
+public abstract class Otp
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [Otp](simpleotp.otp)
+Attributes [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute)
+
+## Properties
+
+### **Secret**
+
+Gets or sets the secret key used for generating OTPs.
+
+```csharp
+public OtpSecret Secret { get; set; }
+```
+
+#### Property Value
+
+[OtpSecret](simpleotp.otpsecret)
+
+### **Algorithm**
+
+Gets or sets the algorithm used for generating OTP codes.
+
+```csharp
+public OtpAlgorithm Algorithm { get; set; }
+```
+
+#### Property Value
+
+[OtpAlgorithm](simpleotp.otpalgorithm)
+
+### **Digits**
+
+Gets or sets the number of digits in the OTP code.
+
+```csharp
+public int Digits { get; set; }
+```
+
+#### Property Value
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+Default: 6. Recommended: 6-8.
+
+## Constructors
+
+### **Otp(OtpSecret, OtpAlgorithm, Int32)**
+
+Initializes a new instance of the [Otp](simpleotp.otp) class.
+
+```csharp
+public Otp(OtpSecret secret, OtpAlgorithm algorithm, int digits)
+```
+
+#### Parameters
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret key used for generating OTP codes.
+
+`algorithm` [OtpAlgorithm](simpleotp.otpalgorithm)
+The algorithm used for generating OTP codes.
+
+`digits` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The number of digits in the OTP code.
+
+### **Otp(OtpSecret, OtpAlgorithm)**
+
+Initializes a new instance of the [Otp](simpleotp.otp) class.
+
+```csharp
+public Otp(OtpSecret secret, OtpAlgorithm algorithm)
+```
+
+#### Parameters
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret key used for generating OTP codes.
+
+`algorithm` [OtpAlgorithm](simpleotp.otpalgorithm)
+The algorithm used for generating OTP codes.
+
+### **Otp(OtpSecret, Int32)**
+
+Initializes a new instance of the [Otp](simpleotp.otp) class.
+
+```csharp
+public Otp(OtpSecret secret, int digits)
+```
+
+#### Parameters
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret key used for generating OTP codes.
+
+`digits` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The number of digits in the OTP code.
+
+### **Otp(OtpSecret)**
+
+Initializes a new instance of the [Otp](simpleotp.otp) class.
+
+```csharp
+public Otp(OtpSecret secret)
+```
+
+#### Parameters
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret key used for generating OTP codes.
+
+## Methods
+
+### **Generate()**
+
+Generates an OTP code.
+
+```csharp
+public OtpCode Generate()
+```
+
+#### Returns
+
+[OtpCode](simpleotp.otpcode)
+The generated OTP code.
+
+### **Generate(Int64)**
+
+Generates an OTP code for the specified counter value.
+
+```csharp
+public OtpCode Generate(long counter)
+```
+
+#### Parameters
+
+`counter` [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+The counter value to generate the OTP code for.
+
+#### Returns
+
+[OtpCode](simpleotp.otpcode)
+The generated OTP code.
+
+### **Validate(OtpCode)**
+
+Validates an OTP code.
+
+```csharp
+public bool Validate(OtpCode code)
+```
+
+#### Parameters
+
+`code` [OtpCode](simpleotp.otpcode)
+The OTP code to validate.
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+`true` if the OTP code is valid; otherwise, `false`.
+
+#### Exceptions
+
+[InvalidOperationException](https://docs.microsoft.com/en-us/dotnet/api/system.invalidoperationexception)
+Implementation for the [Otp.Algorithm](simpleotp.otp#algorithm) algorithm was not found.
+ Use [HashAlgorithmProviders.AddProvider(OtpAlgorithm, KeyedHashAlgorithm)](simpleotp.hashalgorithmproviders#addproviderotpalgorithm-keyedhashalgorithm) to register an implementation.
+
+### **Validate(OtpCode, ToleranceSpan)**
+
+Validates an OTP code with tolerance.
+
+```csharp
+public bool Validate(OtpCode code, ToleranceSpan tolerance)
+```
+
+#### Parameters
+
+`code` [OtpCode](simpleotp.otpcode)
+The OTP code to validate.
+
+`tolerance` [ToleranceSpan](simpleotp.tolerancespan)
+The tolerance span for code validation.
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+`true` if the OTP code is valid; otherwise, `false`.
+
+#### Exceptions
+
+[InvalidOperationException](https://docs.microsoft.com/en-us/dotnet/api/system.invalidoperationexception)
+Implementation for the [Otp.Algorithm](simpleotp.otp#algorithm) algorithm was not found.
+ Use [HashAlgorithmProviders.AddProvider(OtpAlgorithm, KeyedHashAlgorithm)](simpleotp.hashalgorithmproviders#addproviderotpalgorithm-keyedhashalgorithm) to register an implementation.
+
+### **Validate(OtpCode, ToleranceSpan, Int32&)**
+
+Validates an OTP code with tolerance and returns the resynchronization value.
+
+```csharp
+public bool Validate(OtpCode code, ToleranceSpan tolerance, Int32& resyncValue)
+```
+
+#### Parameters
+
+`code` [OtpCode](simpleotp.otpcode)
+The OTP code to validate.
+
+`tolerance` [ToleranceSpan](simpleotp.tolerancespan)
+The tolerance span for code validation.
+
+`resyncValue` [Int32&](https://docs.microsoft.com/en-us/dotnet/api/system.int32&)
+The resynchronization value. Indicates how much given OTP code is ahead or behind the current counter value.
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+`true` if the OTP code is valid; otherwise, `false`.
+
+#### Exceptions
+
+[InvalidOperationException](https://docs.microsoft.com/en-us/dotnet/api/system.invalidoperationexception)
+Implementation for the [Otp.Algorithm](simpleotp.otp#algorithm) algorithm was not found.
+ Use [HashAlgorithmProviders.AddProvider(OtpAlgorithm, KeyedHashAlgorithm)](simpleotp.hashalgorithmproviders#addproviderotpalgorithm-keyedhashalgorithm) to register an implementation.
+
+### **Validate(OtpCode, ToleranceSpan, Int64, Int32&)**
+
+Validates an OTP code with tolerance and base counter value, and returns the resynchronization value.
+
+```csharp
+public bool Validate(OtpCode code, ToleranceSpan tolerance, long baseCounter, Int32& resyncValue)
+```
+
+#### Parameters
+
+`code` [OtpCode](simpleotp.otpcode)
+The OTP code to validate.
+
+`tolerance` [ToleranceSpan](simpleotp.tolerancespan)
+The tolerance span for code validation.
+
+`baseCounter` [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+The base counter value.
+
+`resyncValue` [Int32&](https://docs.microsoft.com/en-us/dotnet/api/system.int32&)
+The resynchronization value. Indicates how much given OTP code is ahead or behind the current counter value.
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+`true` if the OTP code is valid; otherwise, `false`.
+
+#### Exceptions
+
+[InvalidOperationException](https://docs.microsoft.com/en-us/dotnet/api/system.invalidoperationexception)
+Implementation for the [Otp.Algorithm](simpleotp.otp#algorithm) algorithm was not found.
+ Use [HashAlgorithmProviders.AddProvider(OtpAlgorithm, KeyedHashAlgorithm)](simpleotp.hashalgorithmproviders#addproviderotpalgorithm-keyedhashalgorithm) to register an implementation.
+
+### **GetCounter()**
+
+Gets the current counter value.
+
+```csharp
+protected abstract long GetCounter()
+```
+
+#### Returns
+
+[Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+The current counter value.
+
+### **Compute(Int64)**
+
+Computes the OTP code for the specified counter value.
+
+```csharp
+protected int Compute(long counter)
+```
+
+#### Parameters
+
+`counter` [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+The counter value to compute the OTP code for.
+
+#### Returns
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The OTP code for the specified counter value.
+
+#### Exceptions
+
+[InvalidOperationException](https://docs.microsoft.com/en-us/dotnet/api/system.invalidoperationexception)
+Implementation for the [Otp.Algorithm](simpleotp.otp#algorithm) algorithm was not found.
+ Use [HashAlgorithmProviders.AddProvider(OtpAlgorithm, KeyedHashAlgorithm)](simpleotp.hashalgorithmproviders#addproviderotpalgorithm-keyedhashalgorithm) to register an implementation.
+
+### **Compute(Int64, KeyedHashAlgorithm)**
+
+Computes the OTP code for the specified counter value using provided hash algorithm.
+
+```csharp
+protected int Compute(long counter, KeyedHashAlgorithm hashAlgorithm)
+```
+
+#### Parameters
+
+`counter` [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+The counter value to compute the OTP code for.
+
+`hashAlgorithm` KeyedHashAlgorithm
+The hash algorithm to use for computing the OTP code.
+
+#### Returns
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The OTP code for the specified counter value.
+
+**Remarks:**
+
+You need to dispose of the `hashAlgorithm` object yourself when you are done using it.
diff --git a/simpleotp.otpalgorithm.md b/simpleotp.otpalgorithm.md
new file mode 100644
index 0000000..512deb3
--- /dev/null
+++ b/simpleotp.otpalgorithm.md
@@ -0,0 +1,236 @@
+# OtpAlgorithm
+
+Namespace: SimpleOTP
+
+Represents the hashing algorithm used for One-Time Passwords.
+
+```csharp
+public struct OtpAlgorithm
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [ValueType](https://docs.microsoft.com/en-us/dotnet/api/system.valuetype) → [OtpAlgorithm](simpleotp.otpalgorithm)
+Implements [IEquatable<OtpAlgorithm>](https://docs.microsoft.com/en-us/dotnet/api/system.iequatable-1), [IEquatable<String>](https://docs.microsoft.com/en-us/dotnet/api/system.iequatable-1), IXmlSerializable
+Attributes [SerializableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.serializableattribute), [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute), [IsReadOnlyAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.isreadonlyattribute), JsonConverterAttribute
+
+## Properties
+
+### **SHA1**
+
+The HMAC-SHA1 hashing algorithm.
+
+```csharp
+public static OtpAlgorithm SHA1 { get; }
+```
+
+#### Property Value
+
+[OtpAlgorithm](simpleotp.otpalgorithm)
+
+### **SHA256**
+
+The HMAC-SHA256 hashing algorithm.
+
+```csharp
+public static OtpAlgorithm SHA256 { get; }
+```
+
+#### Property Value
+
+[OtpAlgorithm](simpleotp.otpalgorithm)
+
+### **SHA512**
+
+The HMAC-SHA512 hashing algorithm.
+
+```csharp
+public static OtpAlgorithm SHA512 { get; }
+```
+
+#### Property Value
+
+[OtpAlgorithm](simpleotp.otpalgorithm)
+
+### **MD5**
+
+The HMAC-MD5 hashing algorithm.
+
+```csharp
+public static OtpAlgorithm MD5 { get; }
+```
+
+#### Property Value
+
+[OtpAlgorithm](simpleotp.otpalgorithm)
+
+**Remarks:**
+
+This is not a standard algorithm, but it is defined by IIJ specification and recognized by default.
Internet Initiative Japan. URI format
+
+## Constructors
+
+### **OtpAlgorithm(String)**
+
+Initializes a new instance of the [OtpAlgorithm](simpleotp.otpalgorithm) struct.
+
+```csharp
+OtpAlgorithm(string value)
+```
+
+#### Parameters
+
+`value` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The algorithm to use.
+
+#### Exceptions
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+Thrown if `value` is empty or whitespace.
+
+[ArgumentNullException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception)
+Thrown if `value` is .
+
+## Methods
+
+### **Equals(OtpAlgorithm)**
+
+```csharp
+bool Equals(OtpAlgorithm other)
+```
+
+#### Parameters
+
+`other` [OtpAlgorithm](simpleotp.otpalgorithm)
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **Equals(String)**
+
+```csharp
+bool Equals(string other)
+```
+
+#### Parameters
+
+`other` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **Equals(Object)**
+
+```csharp
+bool Equals(object obj)
+```
+
+#### Parameters
+
+`obj` [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object)
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **IsStandard()**
+
+Determines whether the specified [OtpAlgorithm](simpleotp.otpalgorithm) is standard HMAC SHA algorithm (SHA-1, SHA-256 or SHA-512).
+
+```csharp
+bool IsStandard()
+```
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+if the specified [OtpAlgorithm](simpleotp.otpalgorithm) is standard; otherwise, .
+
+### **GetHashCode()**
+
+```csharp
+int GetHashCode()
+```
+
+#### Returns
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+
+### **ToString()**
+
+Returns the string representation of the [OtpAlgorithm](simpleotp.otpalgorithm) struct.
+
+```csharp
+string ToString()
+```
+
+#### Returns
+
+[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The string representation of the [OtpAlgorithm](simpleotp.otpalgorithm) struct.
+
+### **GetSchema()**
+
+```csharp
+XmlSchema GetSchema()
+```
+
+#### Returns
+
+XmlSchema
+
+### **ReadXml(XmlReader)**
+
+```csharp
+void ReadXml(XmlReader reader)
+```
+
+#### Parameters
+
+`reader` XmlReader
+
+### **WriteXml(XmlWriter)**
+
+```csharp
+void WriteXml(XmlWriter writer)
+```
+
+#### Parameters
+
+`writer` XmlWriter
+
+### **IsStandard(String)**
+
+Determines whether the specified [OtpAlgorithm](simpleotp.otpalgorithm) is standard HMAC SHA algorithm (SHA-1, SHA-256 or SHA-512).
+
+```csharp
+bool IsStandard(string algorithm)
+```
+
+#### Parameters
+
+`algorithm` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The algorithm to check.
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+if the specified [OtpAlgorithm](simpleotp.otpalgorithm) is standard; otherwise, .
+
+### **IsStandard(OtpAlgorithm)**
+
+Determines whether the specified [OtpAlgorithm](simpleotp.otpalgorithm) is standard HMAC SHA algorithm (SHA-1, SHA-256 or SHA-512).
+
+```csharp
+bool IsStandard(OtpAlgorithm algorithm)
+```
+
+#### Parameters
+
+`algorithm` [OtpAlgorithm](simpleotp.otpalgorithm)
+The algorithm to check.
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+if the specified [OtpAlgorithm](simpleotp.otpalgorithm) is standard; otherwise, .
diff --git a/simpleotp.otpcode.md b/simpleotp.otpcode.md
new file mode 100644
index 0000000..114250f
--- /dev/null
+++ b/simpleotp.otpcode.md
@@ -0,0 +1,299 @@
+# OtpCode
+
+Namespace: SimpleOTP
+
+Represents a one-time password (OTP) code.
+
+```csharp
+public struct OtpCode
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [ValueType](https://docs.microsoft.com/en-us/dotnet/api/system.valuetype) → [OtpCode](simpleotp.otpcode)
+Implements [IEquatable<OtpCode>](https://docs.microsoft.com/en-us/dotnet/api/system.iequatable-1), [IEquatable<String>](https://docs.microsoft.com/en-us/dotnet/api/system.iequatable-1), IXmlSerializable
+Attributes [SerializableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.serializableattribute), [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute), [IsReadOnlyAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.isreadonlyattribute), JsonConverterAttribute
+
+## Properties
+
+### **CanExpire**
+
+Gets a value indicating whether the OTP code can expire (`true` for TOTP, `false` for HOTP).
+
+```csharp
+public bool CanExpire { get; }
+```
+
+#### Property Value
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **ExpirationTime**
+
+Gets the expiration time of the OTP code (TOTP only).
+
+```csharp
+public Nullable ExpirationTime { get; }
+```
+
+#### Property Value
+
+[Nullable<DateTimeOffset>](https://docs.microsoft.com/en-us/dotnet/api/system.nullable-1)
+
+## Constructors
+
+### **OtpCode(Int32, Int32)**
+
+Initializes a new instance of the [OtpCode](simpleotp.otpcode) struct with the specified value with no expiration time.
+
+```csharp
+OtpCode(int code, int digits)
+```
+
+#### Parameters
+
+`code` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The value of the OTP code.
+
+`digits` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The number of digits in the OTP code.
+
+#### Exceptions
+
+[ArgumentNullException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception)
+`code` is .
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+`code` is not a valid numeric code.
+
+### **OtpCode(Int32, Int32, Nullable<DateTimeOffset>)**
+
+Initializes a new instance of the [OtpCode](simpleotp.otpcode) struct with the specified value and the expiration time.
+
+```csharp
+OtpCode(int code, int digits, Nullable expirationTime)
+```
+
+#### Parameters
+
+`code` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The value of the OTP code.
+
+`digits` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The number of digits in the OTP code.
+
+`expirationTime` [Nullable<DateTimeOffset>](https://docs.microsoft.com/en-us/dotnet/api/system.nullable-1)
+The expiration time of the OTP code (TOTP only).
+
+#### Exceptions
+
+[ArgumentNullException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception)
+`code` is .
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+`code` is not a valid numeric code.
+
+### **OtpCode(String)**
+
+Initializes a new instance of the [OtpCode](simpleotp.otpcode) struct with the specified value with no expiration time.
+
+```csharp
+OtpCode(string code)
+```
+
+#### Parameters
+
+`code` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The value of the OTP code.
+
+#### Exceptions
+
+[ArgumentNullException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception)
+`code` is .
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+`code` is not a valid numeric code.
+
+### **OtpCode(String, Nullable<DateTimeOffset>)**
+
+Initializes a new instance of the [OtpCode](simpleotp.otpcode) struct with the specified value and the expiration time.
+
+```csharp
+OtpCode(string code, Nullable expirationTime)
+```
+
+#### Parameters
+
+`code` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The value of the OTP code.
+
+`expirationTime` [Nullable<DateTimeOffset>](https://docs.microsoft.com/en-us/dotnet/api/system.nullable-1)
+The expiration time of the OTP code (TOTP only).
+
+#### Exceptions
+
+[ArgumentNullException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception)
+`code` is .
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+`code` is not a valid numeric code.
+
+## Methods
+
+### **ToString()**
+
+Returns a string representation of the OTP code.
+
+```csharp
+string ToString()
+```
+
+#### Returns
+
+[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+A string representation of the OTP code.
+
+### **ToString(String)**
+
+Returns a string representation of the OTP code.
+
+```csharp
+string ToString(string format)
+```
+
+#### Parameters
+
+`format` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The format to use.
+
+#### Returns
+
+[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The string representation of the OTP code.
+
+### **Equals(OtpCode)**
+
+```csharp
+bool Equals(OtpCode other)
+```
+
+#### Parameters
+
+`other` [OtpCode](simpleotp.otpcode)
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **Equals(Object)**
+
+```csharp
+bool Equals(object obj)
+```
+
+#### Parameters
+
+`obj` [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object)
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **Equals(String)**
+
+```csharp
+bool Equals(string other)
+```
+
+#### Parameters
+
+`other` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **GetHashCode()**
+
+```csharp
+int GetHashCode()
+```
+
+#### Returns
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+
+### **GetSchema()**
+
+```csharp
+XmlSchema GetSchema()
+```
+
+#### Returns
+
+XmlSchema
+
+### **ReadXml(XmlReader)**
+
+```csharp
+void ReadXml(XmlReader reader)
+```
+
+#### Parameters
+
+`reader` XmlReader
+
+### **WriteXml(XmlWriter)**
+
+```csharp
+void WriteXml(XmlWriter writer)
+```
+
+#### Parameters
+
+`writer` XmlWriter
+
+### **Parse(String)**
+
+Parses the specified [String](https://docs.microsoft.com/en-us/dotnet/api/system.string) into an [OtpCode](simpleotp.otpcode) object.
+
+```csharp
+OtpCode Parse(string code)
+```
+
+#### Parameters
+
+`code` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The string to parse.
+
+#### Returns
+
+[OtpCode](simpleotp.otpcode)
+An [OtpCode](simpleotp.otpcode) object.
+
+#### Exceptions
+
+[ArgumentNullException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception)
+`code` is .
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+`code` is not a valid numeric code.
+
+### **TryParse(String, OtpCode&)**
+
+Tries to parse the specified [String](https://docs.microsoft.com/en-us/dotnet/api/system.string) into an [OtpCode](simpleotp.otpcode) object.
+
+```csharp
+bool TryParse(string code, OtpCode& result)
+```
+
+#### Parameters
+
+`code` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The string to parse.
+
+`result` [OtpCode&](simpleotp.otpcode&)
+The parsed [OtpCode](simpleotp.otpcode) object.
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+if `code` was parsed successfully; otherwise, .
diff --git a/simpleotp.otpconfig.md b/simpleotp.otpconfig.md
new file mode 100644
index 0000000..822287a
--- /dev/null
+++ b/simpleotp.otpconfig.md
@@ -0,0 +1,614 @@
+# OtpConfig
+
+Namespace: SimpleOTP
+
+Represents the configuration for a One-Time Password (OTP).
+
+```csharp
+public class OtpConfig : System.Xml.Serialization.IXmlSerializable, System.IEquatable`1[[SimpleOTP.OtpConfig, SimpleOTP, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]]
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [OtpConfig](simpleotp.otpconfig)
+Implements IXmlSerializable, [IEquatable<OtpConfig>](https://docs.microsoft.com/en-us/dotnet/api/system.iequatable-1)
+Attributes [SerializableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.serializableattribute), [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute), JsonConverterAttribute
+
+## Properties
+
+### **EqualityContract**
+
+```csharp
+protected Type EqualityContract { get; }
+```
+
+#### Property Value
+
+[Type](https://docs.microsoft.com/en-us/dotnet/api/system.type)
+
+### **Type**
+
+Gets or sets the type of the OTP.
+
+```csharp
+public OtpType Type { get; set; }
+```
+
+#### Property Value
+
+[OtpType](simpleotp.otptype)
+Default is: [OtpType.Totp](simpleotp.otptype#totp)
+
+**Remarks:**
+
+Internet-Draft.
IMPORTANT: Some authenticators do not support [OtpType.Hotp](simpleotp.otptype#hotp).
+
+### **IssuerLabel**
+
+Gets or sets the issuer label prefix of the OTP.
+
+```csharp
+public string IssuerLabel { get; set; }
+```
+
+#### Property Value
+
+[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+
+**Remarks:**
+
+-
+-
+-
+
+Internet-Draft.
+
+### **Label**
+
+Gets or sets the label of the OTP.
+
+```csharp
+public string Label { get; set; }
+```
+
+#### Property Value
+
+[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+
+**Remarks:**
+
+Internet-Draft.
+
+### **Secret**
+
+Gets or sets the secret of the OTP.
+
+```csharp
+public OtpSecret Secret { get; set; }
+```
+
+#### Property Value
+
+[OtpSecret](simpleotp.otpsecret)
+Default: 160-bit key. Minimal recommended: 128 bits
+
+**Remarks:**
+
+Internet-Draft
+
+### **Algorithm**
+
+Gets or sets the hashing algorithm of the OTP.
+
+```csharp
+public OtpAlgorithm Algorithm { get; set; }
+```
+
+#### Property Value
+
+[OtpAlgorithm](simpleotp.otpalgorithm)
+Default: [OtpAlgorithm.SHA1](simpleotp.otpalgorithm#sha1)
+
+**Remarks:**
+
+Internet-Draft
IMPORTANT: Some authenticators do not support algorithms other than [OtpAlgorithm.SHA1](simpleotp.otpalgorithm#sha1).
+
+### **Issuer**
+
+Gets or sets the issuer of the OTP. Optional.
+
+```csharp
+public string Issuer { get; set; }
+```
+
+#### Property Value
+
+[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+
+**Remarks:**
+
+-
+-
+
+Internet-Draft
+
+### **Digits**
+
+Gets or sets the number of digits of the OTP codes.
+
+```csharp
+public int Digits { get; set; }
+```
+
+#### Property Value
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+Default: 6. Recommended: 6 or 8
+
+**Remarks:**
+
+Internet-Draft
IMPORTANT: Some authenticators do not support digits other than 6.
+
+### **Counter**
+
+Gets or sets the counter of the OTP. Required for [OtpType.Hotp](simpleotp.otptype#hotp). Ignored for [OtpType.Totp](simpleotp.otptype#totp).
+
+```csharp
+public long Counter { get; set; }
+```
+
+#### Property Value
+
+[Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+Default: 0
+
+**Remarks:**
+
+Internet-Draft
IMPORTANT: Some authenticators do not support [OtpType.Hotp](simpleotp.otptype#hotp).
+
+### **Period**
+
+Gets or sets the period of the OTP in seconds. Optional for [OtpType.Totp](simpleotp.otptype#totp). Ignored for [OtpType.Hotp](simpleotp.otptype#hotp).
+
+```csharp
+public int Period { get; set; }
+```
+
+#### Property Value
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+Default: 30
+
+**Remarks:**
+
+Internet-Draft
IMPORTANT: Some authenticators support only periods of 30 seconds.
+
+### **CustomProperties**
+
+Gets the custom vendor-specified properties of the current OTP configuration.
+
+```csharp
+public NameValueCollection CustomProperties { get; }
+```
+
+#### Property Value
+
+NameValueCollection
+
+**Remarks:**
+
+If set, reserved keys
+ `issuer, digits, counter, secret, period and algorithm`
+ will be removed from the [OtpConfig.CustomProperties](simpleotp.otpconfig#customproperties) upon it's serialization to URI.
Internet-Draft
+
+## Constructors
+
+### **OtpConfig(String)**
+
+Initializes a new instance of the [OtpConfig](simpleotp.otpconfig) class.
+
+```csharp
+public OtpConfig(string label)
+```
+
+#### Parameters
+
+`label` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The label of the OTP config.
+
+### **OtpConfig(String, String)**
+
+Initializes a new instance of the [OtpConfig](simpleotp.otpconfig) class.
+
+```csharp
+public OtpConfig(string label, string issuer)
+```
+
+#### Parameters
+
+`label` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The label of the OTP config.
+
+`issuer` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The issuer of the OTP config.
+
+### **OtpConfig(String, OtpSecret)**
+
+Initializes a new instance of the [OtpConfig](simpleotp.otpconfig) class.
+
+```csharp
+public OtpConfig(string label, OtpSecret secret)
+```
+
+#### Parameters
+
+`label` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The label of the OTP config.
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret of the OTP config.
+
+### **OtpConfig(String, String, OtpSecret)**
+
+Initializes a new instance of the [OtpConfig](simpleotp.otpconfig) class.
+
+```csharp
+public OtpConfig(string label, string issuer, OtpSecret secret)
+```
+
+#### Parameters
+
+`label` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The label of the OTP config.
+
+`issuer` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The issuer of the OTP config.
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret of the OTP config.
+
+### **OtpConfig(Uri)**
+
+Initializes a new instance of the [OtpConfig](simpleotp.otpconfig) class.
+
+```csharp
+public OtpConfig(Uri uri)
+```
+
+#### Parameters
+
+`uri` Uri
+The URI of the OTP config.
+
+#### Exceptions
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+Provided URI is not valid (missing required values or has invalid required values).
+
+### **OtpConfig(Uri, IEncoder)**
+
+Initializes a new instance of the [OtpConfig](simpleotp.otpconfig) class.
+
+```csharp
+public OtpConfig(Uri uri, IEncoder encoder)
+```
+
+#### Parameters
+
+`uri` Uri
+The URI of the OTP config.
+
+`encoder` [IEncoder](simpleotp.encoding.iencoder)
+The encoder used to decode the secret.
+
+#### Exceptions
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+Provided URI is not valid (missing required values or has invalid required values).
+
+### **OtpConfig(OtpConfig)**
+
+```csharp
+protected OtpConfig(OtpConfig original)
+```
+
+#### Parameters
+
+`original` [OtpConfig](simpleotp.otpconfig)
+
+## Methods
+
+### **ToUri()**
+
+Converts the current [OtpConfig](simpleotp.otpconfig) object to a object.
+
+```csharp
+public Uri ToUri()
+```
+
+#### Returns
+
+Uri
+A object representing the current [OtpConfig](simpleotp.otpconfig) object.
+
+**Remarks:**
+
+Uses minimal Google specified formatting ([OtpUriFormat.Minimal](simpleotp.otpuriformat#minimal) | [OtpUriFormat.Google](simpleotp.otpuriformat#google)).
+
+### **ToUri(OtpUriFormat)**
+
+Converts the current [OtpConfig](simpleotp.otpconfig) object to a object.
+
+```csharp
+public Uri ToUri(OtpUriFormat format)
+```
+
+#### Parameters
+
+`format` [OtpUriFormat](simpleotp.otpuriformat)
+A bitwise combination of the enumeration values that specifies the format of the URI.
+
+#### Returns
+
+Uri
+A object representing the current [OtpConfig](simpleotp.otpconfig) object.
+
+### **IsValid(String&, OtpUriFormat)**
+
+Returns if the specified [OtpConfig](simpleotp.otpconfig) object is valid.
+
+```csharp
+public void IsValid(String& error, OtpUriFormat format)
+```
+
+#### Parameters
+
+`error` [String&](https://docs.microsoft.com/en-us/dotnet/api/system.string&)
+The error message returned if the [OtpConfig](simpleotp.otpconfig) object is invalid.
+
+`format` [OtpUriFormat](simpleotp.otpuriformat)
+The [OtpUriFormat](simpleotp.otpuriformat) to use for validation.
+
+### **ToString()**
+
+```csharp
+public string ToString()
+```
+
+#### Returns
+
+[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+
+### **GetSchema()**
+
+```csharp
+public XmlSchema GetSchema()
+```
+
+#### Returns
+
+XmlSchema
+
+### **ReadXml(XmlReader)**
+
+```csharp
+public void ReadXml(XmlReader reader)
+```
+
+#### Parameters
+
+`reader` XmlReader
+
+### **WriteXml(XmlWriter)**
+
+```csharp
+public void WriteXml(XmlWriter writer)
+```
+
+#### Parameters
+
+`writer` XmlWriter
+
+### **ParseUri(Uri)**
+
+Parses the specified URI into an [OtpConfig](simpleotp.otpconfig) object.
+
+```csharp
+public static OtpConfig ParseUri(Uri uri)
+```
+
+#### Parameters
+
+`uri` Uri
+The URI to parse.
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+An [OtpConfig](simpleotp.otpconfig) object parsed from the specified URI.
+
+#### Exceptions
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+Provided URI is not valid (missing required values or has invalid required values).
+
+### **ParseUri(Uri, IEncoder)**
+
+Initializes a new instance of the [OtpConfig](simpleotp.otpconfig) class.
+
+```csharp
+public static OtpConfig ParseUri(Uri uri, IEncoder encoder)
+```
+
+#### Parameters
+
+`uri` Uri
+The URI of the OTP.
+
+`encoder` [IEncoder](simpleotp.encoding.iencoder)
+The encoder used to decode the secret.
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+
+#### Exceptions
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+Provided URI is not valid (missing required values or has invalid required values).
+
+### **ParseUri(String)**
+
+Parses the specified URI into an [OtpConfig](simpleotp.otpconfig) object.
+
+```csharp
+public static OtpConfig ParseUri(string uri)
+```
+
+#### Parameters
+
+`uri` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The URI to parse.
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
+An [OtpConfig](simpleotp.otpconfig) object parsed from the specified URI.
+
+#### Exceptions
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+Provided URI is not valid (missing required values or has invalid required values).
+
+T:System.UriFormatException
+Provided URI is not valid (missing required values or has invalid required values).
+
+### **TryParseUri(Uri, OtpConfig&)**
+
+Tries to parse the specified URI into an [OtpConfig](simpleotp.otpconfig) object.
+
+```csharp
+public static bool TryParseUri(Uri uri, OtpConfig& config)
+```
+
+#### Parameters
+
+`uri` Uri
+The URI to parse.
+
+`config` [OtpConfig&](simpleotp.otpconfig&)
+When this method returns, contains the [OtpConfig](simpleotp.otpconfig) object parsed from the specified URI, if the conversion succeeded, or `null` if the conversion failed.
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+`true` if the conversion succeeded; otherwise, `false`.
+
+### **TryParseUri(String, OtpConfig&)**
+
+Tries to parse the specified URI into an [OtpConfig](simpleotp.otpconfig) object.
+
+```csharp
+public static bool TryParseUri(string uri, OtpConfig& config)
+```
+
+#### Parameters
+
+`uri` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The URI to parse.
+
+`config` [OtpConfig&](simpleotp.otpconfig&)
+When this method returns, contains the [OtpConfig](simpleotp.otpconfig) object parsed from the specified URI, if the conversion succeeded, or `null` if the conversion failed.
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+`true` if the conversion succeeded; otherwise, `false`.
+
+### **Validate(OtpConfig, String&, OtpUriFormat)**
+
+Returns if the specified [OtpConfig](simpleotp.otpconfig) object is valid.
+
+```csharp
+public static bool Validate(OtpConfig config, String& error, OtpUriFormat format)
+```
+
+#### Parameters
+
+`config` [OtpConfig](simpleotp.otpconfig)
+The [OtpConfig](simpleotp.otpconfig) object to validate.
+
+`error` [String&](https://docs.microsoft.com/en-us/dotnet/api/system.string&)
+The error message returned if the [OtpConfig](simpleotp.otpconfig) object is invalid.
+
+`format` [OtpUriFormat](simpleotp.otpuriformat)
+The [OtpUriFormat](simpleotp.otpuriformat) to use for validation.
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+`true` if the conversion succeeded; otherwise, `false`.
+
+**Remarks:**
+
+The `format` should contain at least one vendor-specific format.
+
+### **PrintMembers(StringBuilder)**
+
+```csharp
+protected bool PrintMembers(StringBuilder builder)
+```
+
+#### Parameters
+
+`builder` [StringBuilder](https://docs.microsoft.com/en-us/dotnet/api/system.text.stringbuilder)
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **GetHashCode()**
+
+```csharp
+public int GetHashCode()
+```
+
+#### Returns
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+
+### **Equals(Object)**
+
+```csharp
+public bool Equals(object obj)
+```
+
+#### Parameters
+
+`obj` [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object)
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **Equals(OtpConfig)**
+
+```csharp
+public bool Equals(OtpConfig other)
+```
+
+#### Parameters
+
+`other` [OtpConfig](simpleotp.otpconfig)
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **<Clone>$()**
+
+```csharp
+public OtpConfig $()
+```
+
+#### Returns
+
+[OtpConfig](simpleotp.otpconfig)
diff --git a/simpleotp.otpsecret.md b/simpleotp.otpsecret.md
new file mode 100644
index 0000000..55bbc28
--- /dev/null
+++ b/simpleotp.otpsecret.md
@@ -0,0 +1,434 @@
+# OtpSecret
+
+Namespace: SimpleOTP
+
+Represents a one-time password secret.
+
+```csharp
+public class OtpSecret : System.IEquatable`1[[SimpleOTP.OtpSecret, SimpleOTP, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]], System.IEquatable`1[[System.Byte[], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Xml.Serialization.IXmlSerializable, System.IDisposable
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [OtpSecret](simpleotp.otpsecret)
+Implements [IEquatable<OtpSecret>](https://docs.microsoft.com/en-us/dotnet/api/system.iequatable-1), [IEquatable<Byte[]>](https://docs.microsoft.com/en-us/dotnet/api/system.iequatable-1), IXmlSerializable, [IDisposable](https://docs.microsoft.com/en-us/dotnet/api/system.idisposable)
+Attributes [SerializableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.serializableattribute), [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute), JsonConverterAttribute
+
+## Properties
+
+### **DefaultEncoder**
+
+Gets or sets the default encoder for parsing/encoding/serializing secrets.
+
+```csharp
+public static IEncoder DefaultEncoder { get; set; }
+```
+
+#### Property Value
+
+[IEncoder](simpleotp.encoding.iencoder)
+
+## Constructors
+
+### **OtpSecret()**
+
+Initializes a new instance of the [OtpSecret](simpleotp.otpsecret) class with a default length of 20 bytes (160 bits).
+
+```csharp
+public OtpSecret()
+```
+
+### **OtpSecret(Int32)**
+
+Initializes a new instance of the [OtpSecret](simpleotp.otpsecret) class with a random secret of the specified length.
+
+```csharp
+public OtpSecret(int length)
+```
+
+#### Parameters
+
+`length` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The length of the secret in bytes.
+
+#### Exceptions
+
+[ArgumentOutOfRangeException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentoutofrangeexception)
+`length` is less than 1.
+
+**Remarks:**
+
+20 bytes (160 bits) is the recommended key length specified by RFC 4226.
+ Minimal recommended length is 16 bytes (128 bits).
+
+### **OtpSecret(Byte[])**
+
+Initializes a new instance of the [OtpSecret](simpleotp.otpsecret) class from a byte array.
+
+```csharp
+public OtpSecret(Byte[] secret)
+```
+
+#### Parameters
+
+`secret` [Byte[]](https://docs.microsoft.com/en-us/dotnet/api/system.byte)
+The byte array.
+
+#### Exceptions
+
+[ArgumentNullException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception)
+`secret` is `null` or empty.
+
+### **OtpSecret(String)**
+
+Initializes a new instance of the [OtpSecret](simpleotp.otpsecret) class from a Base32-encoded string (RFC 4648 §6).
+
+```csharp
+public OtpSecret(string secret)
+```
+
+#### Parameters
+
+`secret` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The Base32-encoded string.
+
+#### Exceptions
+
+[ArgumentNullException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception)
+`secret` is `null`.
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+`secret` is empty or contains invalid characters or only whitespace.
+
+### **OtpSecret(String, IEncoder)**
+
+Initializes a new instance of the [OtpSecret](simpleotp.otpsecret) class from an encoded string.
+
+```csharp
+public OtpSecret(string secret, IEncoder encoder)
+```
+
+#### Parameters
+
+`secret` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The encoded string.
+
+`encoder` [IEncoder](simpleotp.encoding.iencoder)
+The encoder.
+
+#### Exceptions
+
+[ArgumentNullException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception)
+`secret` is `null` or empty.
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+`secret` is empty or contains invalid characters or only whitespace.
+
+## Methods
+
+### **ToString()**
+
+Returns the Base32-encoded string representation of the current [OtpSecret](simpleotp.otpsecret) object.
+
+```csharp
+public string ToString()
+```
+
+#### Returns
+
+[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The Base32-encoded string representation of the current [OtpSecret](simpleotp.otpsecret) object.
+
+### **ToString(IEncoder)**
+
+Returns the string representation of the current [OtpSecret](simpleotp.otpsecret) object.
+
+```csharp
+public string ToString(IEncoder encoder)
+```
+
+#### Parameters
+
+`encoder` [IEncoder](simpleotp.encoding.iencoder)
+The encoder.
+
+#### Returns
+
+[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The string representation of the current [OtpSecret](simpleotp.otpsecret) object.
+
+### **Equals(OtpSecret)**
+
+```csharp
+public bool Equals(OtpSecret other)
+```
+
+#### Parameters
+
+`other` [OtpSecret](simpleotp.otpsecret)
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **Equals(Object)**
+
+```csharp
+public bool Equals(object obj)
+```
+
+#### Parameters
+
+`obj` [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object)
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **Equals(Byte[])**
+
+```csharp
+public bool Equals(Byte[] other)
+```
+
+#### Parameters
+
+`other` [Byte[]](https://docs.microsoft.com/en-us/dotnet/api/system.byte)
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **GetHashCode()**
+
+```csharp
+public int GetHashCode()
+```
+
+#### Returns
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+
+### **Dispose()**
+
+```csharp
+public void Dispose()
+```
+
+### **GetSchema()**
+
+```csharp
+public XmlSchema GetSchema()
+```
+
+#### Returns
+
+XmlSchema
+
+### **ReadXml(XmlReader)**
+
+```csharp
+public void ReadXml(XmlReader reader)
+```
+
+#### Parameters
+
+`reader` XmlReader
+
+### **WriteXml(XmlWriter)**
+
+```csharp
+public void WriteXml(XmlWriter writer)
+```
+
+#### Parameters
+
+`writer` XmlWriter
+
+### **CreateCopy(OtpSecret)**
+
+Creates a copy of the specified [OtpSecret](simpleotp.otpsecret) object.
+
+```csharp
+public static OtpSecret CreateCopy(OtpSecret source)
+```
+
+#### Parameters
+
+`source` [OtpSecret](simpleotp.otpsecret)
+The [OtpSecret](simpleotp.otpsecret) object to copy.
+
+#### Returns
+
+[OtpSecret](simpleotp.otpsecret)
+A copy of the specified [OtpSecret](simpleotp.otpsecret) object.
+
+### **CreateNew()**
+
+Creates a new random [OtpSecret](simpleotp.otpsecret) object with a default length of 20 bytes.
+
+```csharp
+public static OtpSecret CreateNew()
+```
+
+#### Returns
+
+[OtpSecret](simpleotp.otpsecret)
+A new random [OtpSecret](simpleotp.otpsecret) object.
+
+**Remarks:**
+
+20 bytes (160 bits) is the recommended key length specified by RFC 4226.
+ Minimal recommended length is 16 bytes (128 bits).
+
+### **CreateNew(Int32)**
+
+Creates a new random [OtpSecret](simpleotp.otpsecret) object with the specified length.
+
+```csharp
+public static OtpSecret CreateNew(int length)
+```
+
+#### Parameters
+
+`length` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The length of the secret in bytes.
+
+#### Returns
+
+[OtpSecret](simpleotp.otpsecret)
+A new random [OtpSecret](simpleotp.otpsecret) object.
+
+#### Exceptions
+
+[ArgumentOutOfRangeException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentoutofrangeexception)
+`length` is less than 1.
+
+**Remarks:**
+
+20 bytes (160 bits) is the recommended key length specified by RFC 4226.
+ Minimal recommended length is 16 bytes (128 bits).
+
+### **Parse(String)**
+
+Parses a Base32-encoded string into an [OtpSecret](simpleotp.otpsecret) object.
+
+```csharp
+public static OtpSecret Parse(string secret)
+```
+
+#### Parameters
+
+`secret` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The Base32-encoded string.
+
+#### Returns
+
+[OtpSecret](simpleotp.otpsecret)
+An [OtpSecret](simpleotp.otpsecret) object.
+
+#### Exceptions
+
+[ArgumentNullException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception)
+`secret` is `null`.
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+`secret` is empty or contains invalid characters or only whitespace.
+
+### **Parse(String, IEncoder)**
+
+Parses a Base32-encoded string into an [OtpSecret](simpleotp.otpsecret) object.
+
+```csharp
+public static OtpSecret Parse(string secret, IEncoder encoder)
+```
+
+#### Parameters
+
+`secret` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The Base32-encoded string.
+
+`encoder` [IEncoder](simpleotp.encoding.iencoder)
+The encoder.
+
+#### Returns
+
+[OtpSecret](simpleotp.otpsecret)
+An [OtpSecret](simpleotp.otpsecret) object.
+
+#### Exceptions
+
+[ArgumentNullException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception)
+`secret` is `null`.
+
+[ArgumentException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentexception)
+`secret` is empty or contains invalid characters or only whitespace.
+
+### **TryParse(String, OtpSecret&)**
+
+Tries to parse a Base32-encoded string into an [OtpSecret](simpleotp.otpsecret) object.
+
+```csharp
+public static bool TryParse(string secret, OtpSecret& otpSecret)
+```
+
+#### Parameters
+
+`secret` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The Base32-encoded string.
+
+`otpSecret` [OtpSecret&](simpleotp.otpsecret&)
+When this method returns, contains the [OtpSecret](simpleotp.otpsecret) object, if the conversion succeeded, or `default` if the conversion failed.
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+`true` if `secret` was converted successfully; otherwise, `false`.
+
+### **TryParse(String, IEncoder, OtpSecret&)**
+
+Tries to parse a Base32-encoded string into an [OtpSecret](simpleotp.otpsecret) object.
+
+```csharp
+public static bool TryParse(string secret, IEncoder encoder, OtpSecret& otpSecret)
+```
+
+#### Parameters
+
+`secret` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The Base32-encoded string.
+
+`encoder` [IEncoder](simpleotp.encoding.iencoder)
+The encoder.
+
+`otpSecret` [OtpSecret&](simpleotp.otpsecret&)
+When this method returns, contains the [OtpSecret](simpleotp.otpsecret) object, if the conversion succeeded, or `default` if the conversion failed.
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+`true` if `secret` was converted successfully; otherwise, `false`.
+
+### **FromBytes(Byte[])**
+
+Creates a new [OtpSecret](simpleotp.otpsecret) object from a byte array.
+
+```csharp
+public static OtpSecret FromBytes(Byte[] secret)
+```
+
+#### Parameters
+
+`secret` [Byte[]](https://docs.microsoft.com/en-us/dotnet/api/system.byte)
+The byte array.
+
+#### Returns
+
+[OtpSecret](simpleotp.otpsecret)
+An [OtpSecret](simpleotp.otpsecret) object.
+
+#### Exceptions
+
+[ArgumentNullException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception)
+`secret` is `null`.
+
+[ArgumentOutOfRangeException](https://docs.microsoft.com/en-us/dotnet/api/system.argumentoutofrangeexception)
+`secret` is empty.
diff --git a/simpleotp.otptype.md b/simpleotp.otptype.md
new file mode 100644
index 0000000..d8b8fc3
--- /dev/null
+++ b/simpleotp.otptype.md
@@ -0,0 +1,19 @@
+# OtpType
+
+Namespace: SimpleOTP
+
+Represents the type of One-Time Password (OTP).
+
+```csharp
+public enum OtpType
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [ValueType](https://docs.microsoft.com/en-us/dotnet/api/system.valuetype) → [Enum](https://docs.microsoft.com/en-us/dotnet/api/system.enum) → [OtpType](simpleotp.otptype)
+Implements [IComparable](https://docs.microsoft.com/en-us/dotnet/api/system.icomparable), [ISpanFormattable](https://docs.microsoft.com/en-us/dotnet/api/system.ispanformattable), [IFormattable](https://docs.microsoft.com/en-us/dotnet/api/system.iformattable), [IConvertible](https://docs.microsoft.com/en-us/dotnet/api/system.iconvertible)
+
+## Fields
+
+| Name | Value | Description |
+| --- | --: | --- |
+| Totp | 0 | Time-based One-Time Password (TOTP). |
+| Hotp | 1 | HMAC-based One-Time Password (HOTP). |
diff --git a/simpleotp.otpuriformat.md b/simpleotp.otpuriformat.md
new file mode 100644
index 0000000..1d74348
--- /dev/null
+++ b/simpleotp.otpuriformat.md
@@ -0,0 +1,24 @@
+# OtpUriFormat
+
+Namespace: SimpleOTP
+
+Bitwise flags for specifying the format of One-Time Password (OTP) URIs.
+
+```csharp
+public enum OtpUriFormat
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [ValueType](https://docs.microsoft.com/en-us/dotnet/api/system.valuetype) → [Enum](https://docs.microsoft.com/en-us/dotnet/api/system.enum) → [OtpUriFormat](simpleotp.otpuriformat)
+Implements [IComparable](https://docs.microsoft.com/en-us/dotnet/api/system.icomparable), [ISpanFormattable](https://docs.microsoft.com/en-us/dotnet/api/system.ispanformattable), [IFormattable](https://docs.microsoft.com/en-us/dotnet/api/system.iformattable), [IConvertible](https://docs.microsoft.com/en-us/dotnet/api/system.iconvertible)
+
+## Fields
+
+| Name | Value | Description |
+| --- | --: | --- |
+| Minimal | 1 | Represents a minimal URI format - only non-default properties are included. |
+| Full | 2 | Represents a full URI format - all properties are included. |
+| Google | 16 | Represents a Google URI format. |
+| Apple | 32 | Represents an Apple URI format. |
+| IBM | 64 | Represents an IBM URI format. |
+| Yubico | 128 | Represents a Yubico URI format. |
+| IIJ | 256 | Represents an IIJ URI format. |
diff --git a/simpleotp.tolerancespan.md b/simpleotp.tolerancespan.md
new file mode 100644
index 0000000..5debaa9
--- /dev/null
+++ b/simpleotp.tolerancespan.md
@@ -0,0 +1,137 @@
+# ToleranceSpan
+
+Namespace: SimpleOTP
+
+Represents a span of tolerance values used in OTP (One-Time Password) validation.
+
+```csharp
+public struct ToleranceSpan
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [ValueType](https://docs.microsoft.com/en-us/dotnet/api/system.valuetype) → [ToleranceSpan](simpleotp.tolerancespan)
+Implements [IEquatable<ToleranceSpan>](https://docs.microsoft.com/en-us/dotnet/api/system.iequatable-1)
+Attributes [IsReadOnlyAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.isreadonlyattribute)
+
+## Properties
+
+### **Default**
+
+Gets the default recommended [ToleranceSpan](simpleotp.tolerancespan) value.
+
+```csharp
+public static ToleranceSpan Default { get; }
+```
+
+#### Property Value
+
+[ToleranceSpan](simpleotp.tolerancespan)
+The default [ToleranceSpan](simpleotp.tolerancespan) value: 1 counter/period ahead and behind.
+
+### **Behind**
+
+Gets the number of tolerance values behind the current value.
+
+```csharp
+public int Behind { get; set; }
+```
+
+#### Property Value
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+
+### **Ahead**
+
+Gets the number of tolerance values ahead of the current value.
+
+```csharp
+public int Ahead { get; set; }
+```
+
+#### Property Value
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+
+## Constructors
+
+### **ToleranceSpan(Int32, Int32)**
+
+Represents a span of tolerance values used in OTP (One-Time Password) validation.
+
+```csharp
+ToleranceSpan(int behind, int ahead)
+```
+
+#### Parameters
+
+`behind` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The number of periods/counter values behind the current value.
+
+`ahead` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The number of periods/counter values ahead of the current value.
+
+### **ToleranceSpan(Int32)**
+
+Initializes a new instance of the [ToleranceSpan](simpleotp.tolerancespan) struct with the specified tolerance value.
+ The [ToleranceSpan.Behind](simpleotp.tolerancespan#behind) and [ToleranceSpan.Ahead](simpleotp.tolerancespan#ahead) properties will be set to the same value.
+
+```csharp
+ToleranceSpan(int tolerance)
+```
+
+#### Parameters
+
+`tolerance` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The tolerance value to set for both [ToleranceSpan.Behind](simpleotp.tolerancespan#behind) and [ToleranceSpan.Ahead](simpleotp.tolerancespan#ahead).
+
+## Methods
+
+### **Equals(ToleranceSpan)**
+
+```csharp
+bool Equals(ToleranceSpan other)
+```
+
+#### Parameters
+
+`other` [ToleranceSpan](simpleotp.tolerancespan)
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **Equals(Object)**
+
+```csharp
+bool Equals(object obj)
+```
+
+#### Parameters
+
+`obj` [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object)
+
+#### Returns
+
+[Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean)
+
+### **GetHashCode()**
+
+```csharp
+int GetHashCode()
+```
+
+#### Returns
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+
+### **ToString()**
+
+Returns the string representation of the [ToleranceSpan](simpleotp.tolerancespan) struct.
+
+```csharp
+string ToString()
+```
+
+#### Returns
+
+[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The string representation of the [ToleranceSpan](simpleotp.tolerancespan) struct.
diff --git a/simpleotp.totp.md b/simpleotp.totp.md
new file mode 100644
index 0000000..3276657
--- /dev/null
+++ b/simpleotp.totp.md
@@ -0,0 +1,209 @@
+# Totp
+
+Namespace: SimpleOTP
+
+Represents a Time-based One-Time Password (TOTP) generator.
+
+```csharp
+public class Totp : Otp
+```
+
+Inheritance [Object](https://docs.microsoft.com/en-us/dotnet/api/system.object) → [Otp](simpleotp.otp) → [Totp](simpleotp.totp)
+Attributes [NullableContextAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullablecontextattribute), [NullableAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.nullableattribute)
+
+## Properties
+
+### **Period**
+
+Gets or sets the time period (in seconds) for which each generated OTP is valid.
+
+```csharp
+public int Period { get; set; }
+```
+
+#### Property Value
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+
+**Remarks:**
+
+Also used to calculate the current counter value.
+
+### **Secret**
+
+Gets or sets the secret key used for generating OTPs.
+
+```csharp
+public OtpSecret Secret { get; set; }
+```
+
+#### Property Value
+
+[OtpSecret](simpleotp.otpsecret)
+
+### **Algorithm**
+
+Gets or sets the algorithm used for generating OTP codes.
+
+```csharp
+public OtpAlgorithm Algorithm { get; set; }
+```
+
+#### Property Value
+
+[OtpAlgorithm](simpleotp.otpalgorithm)
+
+### **Digits**
+
+Gets or sets the number of digits in the OTP code.
+
+```csharp
+public int Digits { get; set; }
+```
+
+#### Property Value
+
+[Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+Default: 6. Recommended: 6-8.
+
+## Constructors
+
+### **Totp(OtpSecret)**
+
+Initializes a new instance of the [Totp](simpleotp.totp) class with the specified secret key.
+
+```csharp
+public Totp(OtpSecret secret)
+```
+
+#### Parameters
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret key used for generating OTP codes.
+
+### **Totp(OtpSecret, Int32)**
+
+Initializes a new instance of the [Totp](simpleotp.totp) class with the specified secret key and number of OTP code digits.
+
+```csharp
+public Totp(OtpSecret secret, int period)
+```
+
+#### Parameters
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret key used for generating OTP codes.
+
+`period` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The time period (in seconds) for which each generated OTP is valid.
+
+### **Totp(OtpSecret, Int32, Int32)**
+
+Initializes a new instance of the [Totp](simpleotp.totp) class with the specified secret key, number of OTP code digits, and time period.
+
+```csharp
+public Totp(OtpSecret secret, int period, int digits)
+```
+
+#### Parameters
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret key used for generating OTP codes.
+
+`period` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The time period (in seconds) for which each generated OTP is valid.
+
+`digits` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The number of digits in the OTP code.
+
+### **Totp(OtpSecret, Int32, OtpAlgorithm)**
+
+Initializes a new instance of the [Totp](simpleotp.totp) class with the specified secret key, hash algorithm, and time period.
+
+```csharp
+public Totp(OtpSecret secret, int period, OtpAlgorithm algorithm)
+```
+
+#### Parameters
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret key used for generating OTP codes.
+
+`period` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The time period (in seconds) for which each generated OTP is valid.
+
+`algorithm` [OtpAlgorithm](simpleotp.otpalgorithm)
+The algorithm used for generating OTP codes.
+
+### **Totp(OtpSecret, Int32, OtpAlgorithm, Int32)**
+
+Initializes a new instance of the [Totp](simpleotp.totp) class with the specified secret key, hash algorithm, number of digits, and time period.
+
+```csharp
+public Totp(OtpSecret secret, int period, OtpAlgorithm algorithm, int digits)
+```
+
+#### Parameters
+
+`secret` [OtpSecret](simpleotp.otpsecret)
+The secret key used for generating OTP codes.
+
+`period` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The time period (in seconds) for which each generated OTP is valid.
+
+`algorithm` [OtpAlgorithm](simpleotp.otpalgorithm)
+The algorithm used for generating OTP codes.
+
+`digits` [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32)
+The number of digits in the OTP code.
+
+## Methods
+
+### **Generate(Int64)**
+
+Generates an OTP based on the specified counter value.
+
+```csharp
+public OtpCode Generate(long counter)
+```
+
+#### Parameters
+
+`counter` [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+The counter value to use for OTP generation.
+
+#### Returns
+
+[OtpCode](simpleotp.otpcode)
+An instance of [OtpCode](simpleotp.otpcode) representing the generated OTP.
+
+### **Generate(DateTimeOffset)**
+
+Generates an OTP based on the specified date and time.
+
+```csharp
+public OtpCode Generate(DateTimeOffset date)
+```
+
+#### Parameters
+
+`date` [DateTimeOffset](https://docs.microsoft.com/en-us/dotnet/api/system.datetimeoffset)
+The date and time to use for OTP generation.
+
+#### Returns
+
+[OtpCode](simpleotp.otpcode)
+An instance of [OtpCode](simpleotp.otpcode) representing the generated OTP.
+
+### **GetCounter()**
+
+Gets the current counter value based on the current UTC time and the configured time period.
+
+```csharp
+protected long GetCounter()
+```
+
+#### Returns
+
+[Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64)
+The current counter value.