Developer guide
Australian sanctions API in C# / .NET: screening and error handling
Build Australian sanctions screening in C# / .NET with a complete HTTP example, explicit source selection, idempotency, safe failures, and review handoffs.
On this page
What this C# / .NET integration does
Australia’s Department of Foreign Affairs and Trade publishes the Consolidated List. A source record supports a list-specific comparison; the applicable Australian measures and activity still need separate assessment.
The client submits a subject, validates the response, and prints only the screening ID, status, and candidate count. It does not approve a customer, resolve an identity, or make a legal decision. A nonzero exit leaves the local operation incomplete.
Prepare the runtime and a synthetic request
Use .NET 8 or later. Save the program as Program.cs and the project file shown below as Screen.csproj. HttpClient and System.Text.Json are included; no provider SDK or third-party JSON library is required.
Save the following as request.json. Mira Calder is an invented subject and sandbox@1 uses synthetic fixtures, not a current production sanctions search. Set SANCTIONSKIT_API_KEY to your test key in the process environment. Set SCREENING_OPERATION_ID to a new persistent identifier for this operation, and reuse it only for an unchanged retry.
{
"subject": {
"name": "Mira Calder",
"entityType": "person",
"birthDate": "1984"
},
"package": "sandbox@1",
"retention": "standard"
}Add the project configuration
Save this as Screen.csproj. These dependencies are for the standalone tutorial, not dependencies to add to SanctionsKit’s website build. Review and lock them under your own maintenance process.
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable></PropertyGroup></Project>Send the request and validate the result
Save the client as Program.cs. The endpoint is fixed to SanctionsKit’s HTTPS API. The example rejects redirects, requires explicit authorization before using a live key, and does not retry automatically. Production integrations should preserve the operation state before the first network call.
// .NET 8+. Backend or trusted CLI. No third-party packages.
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
try
{
var key = Environment.GetEnvironmentVariable("SANCTIONSKIT_API_KEY") ?? "";
var operation = Environment.GetEnvironmentVariable("SCREENING_OPERATION_ID") ?? "";
if (key.Length == 0 || operation.Length == 0) throw new InvalidOperationException("Missing configuration");
if (!key.StartsWith("sk_test_", StringComparison.Ordinal) && !(key.StartsWith("sk_live_", StringComparison.Ordinal)
&& Environment.GetEnvironmentVariable("ALLOW_LIVE_SCREENING") == "yes"))
throw new InvalidOperationException("Live operation not explicitly authorized");
var raw = await File.ReadAllBytesAsync(args.Length > 0 ? args[0] : "../request.sandbox.json");
if (raw.Length > 65536) throw new InvalidDataException("Oversized request");
using var input = JsonDocument.Parse(raw);
var body = input.RootElement;
if (body.ValueKind != JsonValueKind.Object || !body.TryGetProperty("subject", out _) ||
body.TryGetProperty("sources", out _) == body.TryGetProperty("package", out _))
throw new InvalidDataException("Invalid request object");
using var handler = new HttpClientHandler { AllowAutoRedirect = false };
using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(25) };
using var deadline = new CancellationTokenSource(TimeSpan.FromSeconds(30));
using var request = new HttpRequestMessage(HttpMethod.Post, "https://www.sanctionskit.com/api/v1/screenings");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", key);
request.Headers.Add("Idempotency-Key", operation);
request.Content = new StringContent(Encoding.UTF8.GetString(raw), Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, deadline.Token);
if (!response.IsSuccessStatusCode) throw new HttpRequestException("Incomplete HTTP response");
await using var stream = await response.Content.ReadAsStreamAsync(deadline.Token);
using var received = new MemoryStream();
var buffer = new byte[8192]; int read;
while ((read = await stream.ReadAsync(buffer.AsMemory(), deadline.Token)) != 0)
{
if (received.Length + read > 8 * 1024 * 1024) throw new InvalidDataException("Oversized response");
received.Write(buffer, 0, read);
}
using var envelope = JsonDocument.Parse(received.ToArray());
var root = envelope.RootElement;
if (root.ValueKind != JsonValueKind.Object || !root.TryGetProperty("data", out var data) || data.ValueKind != JsonValueKind.Object ||
!data.TryGetProperty("id", out var id) || id.ValueKind != JsonValueKind.String || string.IsNullOrEmpty(id.GetString()) ||
!data.TryGetProperty("status", out var state) || state.ValueKind != JsonValueKind.String ||
!data.TryGetProperty("matches", out var matches) || matches.ValueKind != JsonValueKind.Array)
throw new InvalidDataException("Unexpected screening response");
var status = state.GetString(); var count = matches.GetArrayLength();
if ((status != "potential_match" && status != "no_match") || (status == "no_match" && count != 0) || (status == "potential_match" && count == 0))
throw new InvalidDataException("Inconsistent screening response");
Console.WriteLine(JsonSerializer.Serialize(new { id = id.GetString(), status, candidateCount = count }));
}
catch (Exception)
{
Console.Error.WriteLine("Screening incomplete. Check the operation before retrying.");
Environment.ExitCode = 1;
}Run the client
Run this from the directory containing request.json and the project files. Keep the API key out of committed files and shell tracing. The tutorial’s request-file limit is 64 KiB and its response parsing limit is 8 MiB; these are client safeguards, not claims about API service limits.
Use ResponseHeadersRead with an explicit cancellation token that also covers body reads. Check JsonValueKind before reading a field. In a long-running application, use your established HttpClient lifetime management rather than allocating one client for every customer.
dotnet run --project Screen.csproj -- request.jsonChange to the required production coverage
The documented SanctionsKit identifier is au-consolidated. Use current source metadata to confirm availability and subject compatibility. Do not label a result as an OFAC check merely because the same person may also appear in a U.S. source.
For an authorized production operation, replace the package field with the sources array shown below, supply the actual lawfully held subject details, use a live key, and set ALLOW_LIVE_SCREENING=yes. Keep the complete request in request.json and create a new operation ID. Do not send both sources and package. The fragment below is a coverage change, not a complete request.
{
"sources": [
"au-consolidated"
]
}Preserve the source details a reviewer needs
Preserve source references, aliases, dates, identifiers, and the authority context. A normalized display name is not a replacement for the original listing. Multiple authorities may describe one identity differently; keep their evidence separately traceable.
Retain the screening ID with your internal subject reference. Retrieve the complete evidence through the documented retained-result workflow when authorized; the console summary deliberately does not print raw identity details. A later analyst decision must not overwrite the original screening outcome.
Handle failures and test the source-specific edge cases
Treat HTTP errors, timeouts, malformed JSON, missing fields, unknown statuses, and unavailable required coverage as incomplete checks. A 401 or 403 needs credential or scope correction. A 409 needs idempotency-conflict handling. A 429 needs its specific rate-limit or usage-cap treatment; it is not a no-match result.
Test a subject with several source aliases and a partial date. Verify that the Australian source ID and version remain visible in retained evidence and that a required-source failure does not fall through to another list without disclosure.
Substitute a test HttpMessageHandler and validate cancellation, HTTP failures, and JSON type mismatches. An empty matches array is valid only with the appropriate completed status; missing or object-shaped matches must fail.
- Verify both valid result states and inconsistent status/matches combinations.
- Retry an accepted operation only with its original key and unchanged payload.
- Keep missing identity facts unknown instead of inventing contradictory values.
- Route potential matches into review before the separate business decision.
- Keep secrets, submitted names, and raw error bodies out of routine logs.