.NET against the current router
This is the 2026 C# reference for https://api.unshared.shop/api/.
Use HttpClient (or the wrapper below). Do not call
EnsureSuccessStatusCode() before reading JSON — validation failures are often HTTP 400
with a useful message body.
Base URL:
Token: My Profile for purchase/download routes.
https://api.unshared.shop/api/Token: My Profile for purchase/download routes.
validate, validate_url, info, rarity, and products are public.
Endpoints
POST ?action=validate— multipart. Fields:file,kv_file, orkv_files[]. Raw 16 KB KV or ZIP pack.POST ?action=validate_url— formurl, optionalproductname for expected pack size.GET ?action=info&id={12-digit serial}— UnsharedSHOP share log. Optionalstatus=1|2to record a check.GET ?action=rarity&date=MM-DD-YYGET ?action=products— public catalog withcredit_cost.GET ?action=profile/GET ?action=downloads/POST ?action=purchase— requireX-API-Token.GET ?action=download&token=&txn=— JSON redirect, or addstream=1to receive bytes (extract=1by default).
Auth header
http.DefaultRequestHeaders.Add("X-API-Token", token);
// or: Authorization: Bearer {token}
// or: ?api_token= on the query string (checked first by the server)
Minimal .NET 6+ client
using System.Net.Http.Headers;
using System.Text.Json;
public sealed class UnsharedApiClient : IDisposable
{
private readonly HttpClient _http;
private readonly string _base;
public UnsharedApiClient(string token, string baseUrl = "https://api.unshared.shop/api/")
{
_base = baseUrl.TrimEnd('/') + "/";
_http = new HttpClient { Timeout = TimeSpan.FromSeconds(90) };
if (!string.IsNullOrWhiteSpace(token))
_http.DefaultRequestHeaders.Add("X-API-Token", token);
}
public async Task<JsonElement> ValidateFileAsync(string filePath)
{
using var form = new MultipartFormDataContent();
await using var fs = File.OpenRead(filePath);
using var sc = new StreamContent(fs);
sc.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
form.Add(sc, "file", Path.GetFileName(filePath));
using var res = await _http.PostAsync(_base + "?action=validate", form);
var raw = await res.Content.ReadAsStringAsync();
return JsonDocument.Parse(raw).RootElement.Clone();
}
public async Task<JsonElement> CheckSerialAsync(string serial)
{
using var res = await _http.GetAsync(_base + "?action=info&id=" + Uri.EscapeDataString(serial));
var raw = await res.Content.ReadAsStringAsync();
return JsonDocument.Parse(raw).RootElement.Clone();
}
public void Dispose() => _http.Dispose();
}
Reading a result
using var api = new UnsharedApiClient("YOUR_TOKEN");
var doc = await api.ValidateFileAsync("kv.bin");
if (doc.TryGetProperty("multi", out var multi) && multi.GetBoolean())
{
Console.WriteLine(doc.GetProperty("message").GetString());
foreach (var kv in doc.GetProperty("results").EnumerateArray())
Console.WriteLine($"{kv.GetProperty("serial").GetString()}: {kv.GetProperty("status").GetString()}");
return;
}
if (doc.TryGetProperty("success", out var ok) && ok.GetBoolean())
{
Console.WriteLine(doc.GetProperty("status").GetString());
var serial = doc.TryGetProperty("serial", out var s) ? s.GetString() : null;
if (!string.IsNullOrWhiteSpace(serial))
{
var info = await api.CheckSerialAsync(serial);
Console.WriteLine("UnsharedSHOP shared log: " + info.GetProperty("shared"));
}
if (doc.TryGetProperty("sharing", out var sharing) &&
sharing.TryGetProperty("is_shared", out var partnerShared) && partnerShared.GetBoolean())
{
Console.WriteLine("Listed on a partner database — inspect sharing.shared_partners");
}
}
else
{
Console.WriteLine(doc.TryGetProperty("message", out var m) ? m.GetString() : "Validation failed");
}
ZIP and KVChecker fields
- Multiple 16 KB files in one ZIP are valid. You get
results[], not an error. partner_checksis keyed by partner name.first_seenset means a hit;checked: truewith a null date means they looked and found nothing.kvchecker.verify_link/signature(orkvchecker.verifications[]on packs) are the signed proof from KVChecker.com.- Timeouts: live Xbox Live lookups often take several seconds. Set
HttpClient.Timeoutto 90s.
Downloads from C#
After purchase or downloads, call
?action=download&stream=1&token={download_token}&txn={transaction_id}
if you want bytes in-process. Without stream=1 the JSON redirect points at
dl.unshared.shop/kv.bin?id=…&dl=true, which consumes a link use.
Wrapper:
UnsharedApiWrapper.cs
Support ticket if a field changed on your integration.