Developer guide
UK sanctions API in Go: explicit source selection
Select the FCDO list in a Go UK sanctions API request. Keep the source ID explicit and treat missing required coverage as a failed check.

On this page
Keep UK screening coverage explicit in Go
Represent selected coverage as validated configuration rather than accepting arbitrary source names from an untrusted caller. Check the documented source catalog and retain the selected scope with each operation. A service configured for UK screening should not replace unavailable UK coverage with a different list and label the check complete.
Use the current UK Sanctions List context when naming source fields in your own database. Keep historical labels with historical evidence, but make the new source identity visible to reviewers and exported records. The global list directory explains the distinction from the former OFSI feed.
Prepare the synthetic exercise
Create a synthetic Go service configuration that requires uk-sanctions, then mock that source as unavailable. The useful test is whether the operation remains incomplete. A fallback to another country’s list would answer a different question while concealing the missing UK check.
| Requirement | Value or action |
|---|---|
| Runtime | Use Go 1.22 or later. The example uses only the standard library and can run as a small command-line program or be adapted into a backend service. |
| Client file | Save the client as screen.go |
| 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"
}Implement the Go request boundary
The Go CLI submits the source set passed in request.json; it does not choose policy for the caller. Add the documented discovery checks in your trusted service before enabling production requests. Keep source IDs validated separately from user-facing country labels.
// Go 1.22+. Standard library only. Backend or trusted CLI.
package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"time"
)
func run() error {
key, operation := os.Getenv("SANCTIONSKIT_API_KEY"), os.Getenv("SCREENING_OPERATION_ID")
if key == "" || operation == "" { return errors.New("set the API key and a persistent operation ID") }
path := "request.json"
if len(os.Args) > 1 { path = os.Args[1] }
raw, err := os.ReadFile(path)
if err != nil { return errors.New("cannot read request file") }
if len(raw) > 64*1024 { return errors.New("request file exceeds 64 KiB") }
var body map[string]json.RawMessage
if json.Unmarshal(raw, &body) != nil { return errors.New("request is not a JSON object") }
_, sources := body["sources"]; _, pack := body["package"]
if len(body["subject"]) == 0 || sources == pack { return errors.New("supply a subject and exactly one of sources or package") }
request, err := http.NewRequest(http.MethodPost, "https://www.sanctionskit.com/api/v1/screenings", bytes.NewReader(raw))
if err != nil { return err }
request.Header.Set("Authorization", "Bearer "+key)
request.Header.Set("Content-Type", "application/json")
request.Header.Set("Idempotency-Key", operation)
client := &http.Client{
Timeout: 25 * time.Second,
CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse },
}
response, err := client.Do(request)
if err != nil { return errors.New("transport incomplete; check the operation before retrying") }
defer response.Body.Close()
const limit = 8 * 1024 * 1024
payload, err := io.ReadAll(io.LimitReader(response.Body, limit+1))
if err != nil || len(payload) > limit { return errors.New("incomplete or oversized response") }
if response.StatusCode < 200 || response.StatusCode >= 300 { return fmt.Errorf("screening incomplete: HTTP %d", response.StatusCode) }
var envelope struct {
Data *struct {
ID string `json:"id"`
Status string `json:"status"`
Matches []json.RawMessage `json:"matches"`
} `json:"data"`
}
if json.Unmarshal(payload, &envelope) != nil || envelope.Data == nil { return errors.New("invalid response envelope") }
data := envelope.Data
if data.ID == "" || (data.Status != "potential_match" && data.Status != "no_match") || data.Matches == nil {
return errors.New("incomplete response: unexpected screening shape")
}
count := len(data.Matches)
if (data.Status == "no_match" && count != 0) || (data.Status == "potential_match" && count == 0) {
return errors.New("incomplete response: inconsistent screening shape")
}
return json.NewEncoder(os.Stdout).Encode(map[string]any{"id":data.ID,"status":data.Status,"candidateCount":count})
}
func main() {
if err := run(); err != nil { fmt.Fprintln(os.Stderr, err.Error()); os.Exit(1) }
}Run the client
go run screen.go request.jsonConfirm UK sanctions scope before production
This workflow checks the FCDO UK Sanctions List. Store uk-sanctions in configuration and the persisted operation. Keep historical source wording with prior results, while new review screens identify the actual current list and available designation details.
| Check | Required evidence |
|---|---|
| GET /api/v1/sources | Production key with sources:read; response data array |
| id | uk-sanctions |
| 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 uk-sanctions in the production request
| Setting | Production request |
|---|---|
| Key | Separate production credential with screenings:write |
| Coverage | sources: ["uk-sanctions"]; 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": [
"uk-sanctions"
],
"retention": "standard"
}Interpret UK sanctions evidence in this workflow
Use data.coverage to verify the required UK source was included, even when data.matches is empty. A service-level success must not erase a missing source, and a configuration fallback must not relabel another source’s result as a completed UK screening.
| Fields in data.matches[] | Review use |
|---|---|
| record.id and record.sourceId | Retain the UK record reference and source identity when connecting the candidate to your customer. |
| record.names and birthDates | Compare original names and partial dates without inventing missing days or resolving similar names automatically. |
| record.designations | Display the available programs, legal references, effective dates and published wording beside the identity evidence. |
- 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 |
- Mock missing uk-sanctions and assert that the service never submits reduced coverage.
- Reject a caller-provided source display name where an ID is required.
- Check coverage equality before returning a completed application state.
Sources and references
Authority and technical sources
SanctionsKit documentation
Frequently asked questions
Who chooses UK coverage in the Go service?
Your approved backend configuration chooses it. The Go 1.22 HTTP client transports that choice; it does not decide which lists are acceptable substitutes or allow an untrusted caller to remove required coverage.
Can an available non-UK list stand in for a failed UK check?
No. That changes the scope of the screening. Preserve the missing-source error and resume under the required coverage, unless the organization deliberately authorizes and records a different policy.
Can I replace a failed UK source with another list in my Go service?
Do not silently change required coverage. Leave the check incomplete and inspect the source error. Another list answers a different screening question. Resume when the required source is available or your organization deliberately changes its approved scope.
What should a Go UK-coverage contract test assert?
Assert that the request contains the required source and the completed response contains that same source as fresh coverage. Also test absence and mismatch; an empty match array alone does not prove completion.