diff --git a/src/Yllibed.TenantCloudClient/HttpMessages/JsonFlexibleStringConverter.cs b/src/Yllibed.TenantCloudClient/HttpMessages/JsonFlexibleStringConverter.cs
new file mode 100644
index 0000000..88402da
--- /dev/null
+++ b/src/Yllibed.TenantCloudClient/HttpMessages/JsonFlexibleStringConverter.cs
@@ -0,0 +1,44 @@
+using System.Globalization;
+
+namespace Yllibed.TenantCloudClient.HttpMessages;
+
+///
+/// Reads a JSON value that TenantCloud sometimes serializes as a string and
+/// sometimes as a number (observed on property_status) into a string.
+/// Writes back out as a string.
+///
+public class JsonFlexibleStringConverter : JsonConverter
+{
+ public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ switch (reader.TokenType)
+ {
+ case JsonTokenType.String:
+ return reader.GetString();
+ case JsonTokenType.Number:
+ return reader.TryGetInt64(out var l)
+ ? l.ToString(CultureInfo.InvariantCulture)
+ : reader.GetDouble().ToString(CultureInfo.InvariantCulture);
+ case JsonTokenType.True:
+ return "true";
+ case JsonTokenType.False:
+ return "false";
+ case JsonTokenType.Null:
+ return null;
+ default:
+ throw new NotSupportedException($"Type {reader.TokenType} not supported for flexible string");
+ }
+ }
+
+ public override void Write(Utf8JsonWriter writer, string? value, JsonSerializerOptions options)
+ {
+ if (value is null)
+ {
+ writer.WriteNullValue();
+ }
+ else
+ {
+ writer.WriteStringValue(value);
+ }
+ }
+}
diff --git a/src/Yllibed.TenantCloudClient/HttpMessages/JsonNullableDecimalConverter.cs b/src/Yllibed.TenantCloudClient/HttpMessages/JsonNullableDecimalConverter.cs
new file mode 100644
index 0000000..582419f
--- /dev/null
+++ b/src/Yllibed.TenantCloudClient/HttpMessages/JsonNullableDecimalConverter.cs
@@ -0,0 +1,39 @@
+using System.Globalization;
+
+namespace Yllibed.TenantCloudClient.HttpMessages;
+
+///
+/// Reads a JSON decimal value that may also legitimately be null or a
+/// numeric string (observed on unit price). Returns null for a
+/// JSON null and parses strings tolerantly.
+///
+public class JsonNullableDecimalConverter : JsonConverter
+{
+ public override decimal? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ switch (reader.TokenType)
+ {
+ case JsonTokenType.Null:
+ return null;
+ case JsonTokenType.Number:
+ return reader.GetDecimal();
+ case JsonTokenType.String:
+ var str = reader.GetString();
+ return string.IsNullOrWhiteSpace(str) ? null : decimal.Parse(str, CultureInfo.InvariantCulture);
+ default:
+ throw new NotSupportedException($"Type {reader.TokenType} not supported for nullable decimal");
+ }
+ }
+
+ public override void Write(Utf8JsonWriter writer, decimal? value, JsonSerializerOptions options)
+ {
+ if (value is null)
+ {
+ writer.WriteNullValue();
+ }
+ else
+ {
+ writer.WriteNumberValue(value.Value);
+ }
+ }
+}
diff --git a/src/Yllibed.TenantCloudClient/HttpMessages/TcProperty.cs b/src/Yllibed.TenantCloudClient/HttpMessages/TcProperty.cs
index 33e0374..08ecd2a 100644
--- a/src/Yllibed.TenantCloudClient/HttpMessages/TcProperty.cs
+++ b/src/Yllibed.TenantCloudClient/HttpMessages/TcProperty.cs
@@ -16,6 +16,7 @@ public class TcProperty : IHasId
public string? CityAddress { get; set; }
[JsonPropertyName("property_status")]
+ [JsonConverter(typeof(JsonFlexibleStringConverter))]
public string? Status { get; set; }
public string Address => string.Format(CultureInfo.InvariantCulture, "{0} {1}", Address1, CityAddress);
diff --git a/src/Yllibed.TenantCloudClient/HttpMessages/TcUnit.cs b/src/Yllibed.TenantCloudClient/HttpMessages/TcUnit.cs
index 569396f..25efd4e 100644
--- a/src/Yllibed.TenantCloudClient/HttpMessages/TcUnit.cs
+++ b/src/Yllibed.TenantCloudClient/HttpMessages/TcUnit.cs
@@ -11,7 +11,8 @@ public class TcUnit : IHasId
public string? Description { get; set; }
- public decimal Price { get; set; }
+ [JsonConverter(typeof(JsonNullableDecimalConverter))]
+ public decimal? Price { get; set; }
[JsonPropertyName("is_rented")]
public bool IsRented { get; set; }