Developer guide

Canadian sanctions API in Swift: identity review in a backend

Add Canadian autonomous sanctions checks to a Swift backend. Keep API keys on the server and link source records to your identity review.

250 free live screenings. One lifetime allowance. No credit card required.
On this page

Screen Canadian parties with a Swift backend

Keep the known legal name and relevant alternative forms in the customer record with their provenance. Unicode encoding is only one part of data quality: an accented name, a translated business label and a registered legal entity should not be silently treated as interchangeable facts.

The Swift client submits the documented subject fields to SanctionsKit’s selected Canadian source. It does not perform legal translation or determine that a commercial name identifies the same organization. Use the retained source candidate and reliable identifiers when the reviewer compares identities.

Prepare the synthetic exercise

Create a synthetic customer with an accented legal name and a separate display label, then run the Swift CLI with the legal subject. The exercise is about preserving meaning across the app and backend. UTF-8 encoding alone does not prove that two different name forms identify the same party.

Swift setup and request files
RequirementValue or action
RuntimeUse Swift 6 with Foundation. This is a trusted CLI or server-side Swift example. Never embed a SanctionsKit API key in an iPhone, iPad, Apple TV, or macOS client distributed to end users; those apps should call your authenticated backend.
Client fileSave the client as Screen.swift
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 Swift request boundary

Keep URLSession calls and service credentials in the trusted Swift process. Let an installed app send an authorized customer reference to your backend. Do not include candidate evidence in an error description that can escape into client telemetry or crash logs.

Swift: authenticated screening client
// Swift 6. Server or trusted CLI only. Do not ship an API key in an iOS app.
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

struct ScreeningFailure: Error { let message: String }
final class NoRedirect: NSObject, URLSessionTaskDelegate, @unchecked Sendable {
    func urlSession(_ session: URLSession, task: URLSessionTask,
                    willPerformHTTPRedirection response: HTTPURLResponse,
                    newRequest request: URLRequest,
                    completionHandler: @escaping (URLRequest?) -> Void) { completionHandler(nil) }
}
@main struct Screen {
    static func main() async {
        do { try await run() }
        catch {
            // Do not print the request, credential, or raw response.
            FileHandle.standardError.write(Data("Screening incomplete. Check the operation before retrying.\n".utf8))
            exit(1)
        }
    }
    static func run() async throws {
        let env = ProcessInfo.processInfo.environment
        guard let key = env["SANCTIONSKIT_API_KEY"], let operation = env["SCREENING_OPERATION_ID"], !operation.isEmpty else {
            throw ScreeningFailure(message: "Missing credential or operation ID")
        }
        let path = CommandLine.arguments.count > 1 ? CommandLine.arguments[1] : "request.json"
        let raw = try Data(contentsOf: URL(fileURLWithPath: path))
        guard raw.count <= 65_536,
              let body = try JSONSerialization.jsonObject(with: raw) as? [String: Any],
              body["subject"] != nil, (body["sources"] != nil) != (body["package"] != nil) else {
            throw ScreeningFailure(message: "Invalid request object")
        }
        var request = URLRequest(url: URL(string: "https://www.sanctionskit.com/api/v1/screenings")!)
        request.httpMethod = "POST"; request.httpBody = raw
        request.setValue("Bearer \(key)", forHTTPHeaderField: "Authorization")
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.setValue(operation, forHTTPHeaderField: "Idempotency-Key")
        let configuration = URLSessionConfiguration.ephemeral
        configuration.timeoutIntervalForRequest = 25; configuration.timeoutIntervalForResource = 30
        let session = URLSession(configuration: configuration, delegate: NoRedirect(), delegateQueue: nil)
        defer { session.invalidateAndCancel() }
        // URLSession download avoids retaining an unbounded response in memory.
        let (file, response) = try await session.download(for: request)
        defer { try? FileManager.default.removeItem(at: file) }
        let size = try file.resourceValues(forKeys: [.fileSizeKey]).fileSize ?? 0
        guard size <= 8 * 1024 * 1024, let http = response as? HTTPURLResponse,
              (200..<300).contains(http.statusCode) else { throw ScreeningFailure(message: "Incomplete HTTP response") }
        let payload = try Data(contentsOf: file)
        guard let envelope = try JSONSerialization.jsonObject(with: payload) as? [String: Any],
              let data = envelope["data"] as? [String: Any], let id = data["id"] as? String, !id.isEmpty,
              let status = data["status"] as? String, ["potential_match", "no_match"].contains(status),
              let matches = data["matches"] as? [Any],
              (status == "no_match" ? matches.isEmpty : !matches.isEmpty) else {
            throw ScreeningFailure(message: "Unexpected screening response")
        }
        let summary: [String: Any] = ["id":id, "status":status, "candidateCount":matches.count]
        FileHandle.standardOutput.write(try JSONSerialization.data(withJSONObject: summary))
        FileHandle.standardOutput.write(Data("\n".utf8))
    }
}

Run the client

Run the sandbox request
swiftc -parse-as-library Screen.swift -o screen
./screen request.json

Confirm Canadian sanctions scope before production

The production request selects ca-autonomous for autonomous Canadian designations. Keep that scope with the backend result and the available regulation reference. Neither a translated business label nor a party-list comparison resolves every Canadian transaction restriction.

Production source-discovery contract
CheckRequired evidence
GET /api/v1/sourcesProduction key with sources:read; response data array
idca-autonomous
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 ca-autonomous in the production request

Explicit change from the sandbox exercise
SettingProduction request
KeySeparate production credential with screenings:write
Coveragesources: ["ca-autonomous"]; 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 ca-autonomous selection
{
  "subject": {
    "name": "Mira Calder",
    "entityType": "person",
    "birthDate": "1984"
  },
  "sources": [
    "ca-autonomous"
  ],
  "retention": "standard"
}

Interpret Canadian sanctions evidence in this workflow

Use data.id to open the retained result through an authorized review path, with data.coverage and the original source names. Keep legal name, translation and trading label distinct until reliable evidence supports the relationship between them.

Canadian sanctions candidate fields to retain
Fields in data.matches[]Review use
record.id and record.sourceIdKeep the autonomous-list record reference with the returned candidate.
record.designations[].legalReferences and wordingShow the available regulation and published designation context; consult the regulation when reviewing applicable restrictions.
record.names and identifiersKeep bilingual or alternative names and registration details as returned, with missing evidence visibly unknown.
  • 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
  • Round-trip an accented legal name and a separate display label.
  • Verify generic Swift errors omit raw candidate evidence.
  • Open retained evidence through an authorized backend route rather than exposing the service key.

Sources and references

Frequently asked questions

Does Swift Unicode support resolve Canadian name identity?

No. Encoding preserves text, while identity depends on evidence. Keep legal names, translated labels and alternative forms distinct, and compare reliable identifiers before concluding that two forms describe one organization.

Which Canadian list does the Swift production request select?

It selects ca-autonomous, the autonomous designation source. Label the result accordingly and retain any cited regulation; the request is not a substitute for reviewing all restrictions relevant to the planned activity.

Can I show full Canadian match evidence in a Swift app error message?

Keep generic failures separate from the authorized evidence view. Do not include the raw request, key, or complete candidate response in an error shown to the client or written to logs. Fetch retained evidence only through the permitted review workflow.

What belongs in a Swift error shown after Canadian screening fails?

Provide a safe application status and recovery reference. Keep the original request and candidate evidence in authorized storage, rather than embedding sensitive identity details in a client-visible error or routine log.