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.

250 free live screenings. One lifetime allowance. No credit card required.
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.

Go setup and request files
RequirementValue or action
RuntimeUse 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 fileSave the client as screen.go
Screening endpointPOST /api/v1/screenings
SANCTIONSKIT_API_KEYSandbox key; screenings:write and results:read scopes
SCREENING_OPERATION_IDPersist one operation ID; reuse only with the identical request body
request.jsonMira Calder: invented subject; sandbox@1: synthetic records
request.json: synthetic sandbox request
{
  "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: authenticated screening client
// 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

Run the sandbox request
go run screen.go request.json

Confirm 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.

Production source-discovery contract
CheckRequired evidence
GET /api/v1/sourcesProduction key with sources:read; response data array
iduk-sanctions
availability / freshavailable / true
capabilitiesContains the requested subject.entityType
currentVersionActive version; retrieved_at and last_checked_at are not publication dates
lastImportMay describe an import that is not the active version
Missing or ineligible sourceInspect disabledReason; required coverage stays incomplete
Displayed clientAdd these discovery checks before its production call
Read source discovery with your production key
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

Explicit change from the sandbox exercise
SettingProduction request
KeySeparate production credential with screenings:write
Coveragesources: ["uk-sanctions"]; omit package
Operation IDNew ID for the changed body and environment
UsageProduction access and screening allowance apply
SubjectOnly lawfully held, known identifying facts; no invented date precision
request.json: explicit uk-sanctions selection
{
  "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.

UK sanctions candidate fields to retain
Fields in data.matches[]Review use
record.id and record.sourceIdRetain the UK record reference and source identity when connecting the candidate to your customer.
record.names and birthDatesCompare original names and partial dates without inventing missing days or resolving similar names automatically.
record.designationsDisplay 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

Recovery rules for the same saved operation
ConditionNext action
401 / 403Correct credentials or scopes before retrying
coverage_unavailable / stale_coverageKeep required coverage incomplete; no silent source substitution
Timeout after submissionRecover with the original Idempotency-Key and identical body
409Investigate an operation-key conflict
429 / 503Follow the specific error and Retry-After; an allowance cap may require a plan or usage change
Contract and safe diagnostic references
Operational reference
ReferenceUse
error.code / error.requestIdSafe recovery diagnostics; never log the submitted subject, key or full candidate response
potential_match / no_matchCompleted 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

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.