Developer guide
Australian sanctions API in C# / .NET: DFAT data in ASP.NET
Call the Australian sanctions API from an ASP.NET service. Use C# to select DFAT coverage, inspect errors, and retain evidence for review.

On this page
Add Australian screening to an ASP.NET service
An Australian business workflow can span local business dates and provider timestamps. Preserve the actual screening time and source version in your .NET application, and format times for users without replacing the underlying value. A date shown in the local interface should not be mistaken for the authority’s publication date.
For an invented customer correction, retain the time the input changed and the reference of the new operation. This helps reviewers distinguish a new Australian-source comparison from a delayed response to the earlier request.
Prepare the synthetic exercise
Use the synthetic .NET request to test how a screening timestamp appears in an Australian business timezone. Preserve the original instant in storage while changing only its display. A calendar date shown to a reviewer must not be relabeled as the publisher’s list-update date.
| Requirement | Value or action |
|---|---|
| Runtime | 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. |
| Client file | Save the client as Program.cs |
| Screening endpoint | POST /api/v1/screenings |
| SANCTIONSKIT_API_KEY | Sandbox key; screenings:write and results:read scopes |
| SCREENING_OPERATION_ID | Persist one operation ID; reuse only with the identical request body |
| request.json | Mira Calder: invented subject; sandbox@1: synthetic records |
{
"subject": {
"name": "Mira Calder",
"entityType": "person",
"birthDate": "1984"
},
"package": "sandbox@1",
"retention": "standard"
}Add the project configuration
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable></PropertyGroup></Project>Implement the C# / .NET request boundary
The HttpClient adapter should save the provider result independently of the local business-date display. When a customer correction occurs near a date boundary, retain both operation references. A late response to the old operation must not overwrite the corrected customer’s new result.
// .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");
var raw = await File.ReadAllBytesAsync(args.Length > 0 ? args[0] : "request.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
dotnet run --project Screen.csproj -- request.jsonConfirm Australian sanctions scope before production
Select au-consolidated for the DFAT comparison and keep the source version from the completed response. A local date change is not a list update. Coverage freshness and publisher dates need their own fields rather than a timestamp inferred from when the .NET controller ran.
| Check | Required evidence |
|---|---|
| GET /api/v1/sources | Production key with sources:read; response data array |
| id | au-consolidated |
| availability / fresh | available / true |
| capabilities | Contains the requested subject.entityType |
| currentVersion | Active version; retrieved_at and last_checked_at are not publication dates |
| lastImport | May describe an import that is not the active version |
| Missing or ineligible source | Inspect disabledReason; required coverage stays incomplete |
| Displayed client | Add these discovery checks before its production call |
curl --fail-with-body --max-time 25 --header "Authorization: Bearer $SANCTIONSKIT_API_KEY" "https://www.sanctionskit.com/api/v1/sources"Select au-consolidated in the production request
| Setting | Production request |
|---|---|
| Key | Separate production credential with screenings:write |
| Coverage | sources: ["au-consolidated"]; omit package |
| Operation ID | New ID for the changed body and environment |
| Usage | Production access and screening allowance apply |
| Subject | Only lawfully held, known identifying facts; no invented date precision |
{
"subject": {
"name": "Mira Calder",
"entityType": "person",
"birthDate": "1984"
},
"sources": [
"au-consolidated"
],
"retention": "standard"
}Interpret Australian sanctions evidence in this workflow
Write data.id and data.coverage with the original operation time. Format timestamps for the reviewer without losing their underlying value. When comparing old and corrected customer details, show which operation and version produced each result.
| Fields in data.matches[] | Review use |
|---|---|
| record.id and record.names | Retain the DFAT source reference with the primary name and aliases; one listed identity may have several names. |
| record.designations | Display the available designation, program, legal-reference and effective-date context. |
| record.birthDates, identifiers and addresses | Compare the known identity details and retain uncertain dates at the precision supplied. |
- data.id; data.coverage; data.versions; supplied disclaimer
- data.matches[]: record, assessment, evidence, conflicts
- GET /api/v1/results/{id}: results:read scope
- Retained evidence and case review
Verify the application behavior
| Condition | Next action |
|---|---|
| 401 / 403 | Correct credentials or scopes before retrying |
| coverage_unavailable / stale_coverage | Keep required coverage incomplete; no silent source substitution |
| Timeout after submission | Recover with the original Idempotency-Key and identical body |
| 409 | Investigate an operation-key conflict |
| 429 / 503 | Follow the specific error and Retry-After; an allowance cap may require a plan or usage change |
Contract and safe diagnostic references
| Reference | Use |
|---|---|
| error.code / error.requestId | Safe recovery diagnostics; never log the submitted subject, key or full candidate response |
| potential_match / no_match | Completed comparison outcomes; neither is an automatic business approval |
- Display one stored instant in two timezones without changing its value.
- Deliver an older response after a corrected-subject response and preserve both links.
- Keep a missing publisher date unknown rather than using the controller timestamp.
Sources and references
Authority and technical sources
SanctionsKit documentation
Frequently asked questions
Which date should a .NET Australian screening history retain?
Retain the actual operation and result timestamps with their source versions. A local business-date display is useful for people, but it should not replace the underlying instant or stand in for a publisher date.
Does midnight in Australia require a different DFAT source version?
No. A timezone boundary does not establish a source update. Use the completed screening’s coverage and version evidence to describe the data checked, rather than inferring a new dataset from a local calendar date.
Where should a .NET service keep the DFAT screening reference?
Save the returned screening ID with the onboarding operation and your business reference. Keep source coverage, versions, and review state in authorized application storage. The ID lets the team reopen retained evidence without running another check just to view it.
What if an old DFAT response arrives after a C# customer correction?
Link each response to the operation that created it. Keep the corrected subject’s new result separate and preserve the earlier one as history, instead of overwriting whichever customer row happens to be current.