Developer guide

OFAC API in Ruby: background screening jobs

Use the OFAC API in a Ruby background job with Net::HTTP. Save the screening ID and reuse the same operation key when retrying a customer check.

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

Screen OFAC subjects in a Ruby job

A Rails or other Ruby application can enqueue an internal operation reference after persisting the subject, coverage and idempotency key. The worker loads that record and submits the unchanged request. Keep secrets and raw identity details out of job names and routine queue logs.

If the worker restarts after the server accepted the request, recover the same operation under the documented retry rules. A corrected customer name is different: persist the correction and create a new operation with its own key. The job framework’s retry count is not an identity-review decision.

Prepare the synthetic exercise

Enqueue a saved operation for the invented sandbox subject rather than serializing identity details into the job name. Run the Ruby script with that operation key, then test a job restart. The queue entry should point to protected application storage containing the exact original request.

Ruby setup and request files
RequirementValue or action
RuntimeUse Ruby 3.1 or later with its standard JSON, Net::HTTP, URI, and OpenSSL libraries. The script is intended for a backend or trusted CLI and needs no provider SDK.
Client fileSave the client as screen.rb
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 Ruby request boundary

Net::HTTP supplies the transport while your job owns persistence and retries. Its network timeout cannot determine whether an SDN screening was accepted. Store the result before marking the job complete, and avoid allowing a generic job retry to generate a new Idempotency-Key.

Ruby: authenticated screening client
# Ruby 3.1+. Standard library only. Backend or trusted CLI.
require 'json'
require 'net/http'
require 'uri'
require 'openssl'
begin
  key = ENV.fetch('SANCTIONSKIT_API_KEY')
  operation = ENV.fetch('SCREENING_OPERATION_ID')
  raise 'Operation ID must not be empty.' if operation.empty?
  raw = File.binread(ARGV[0] || 'request.json')
  raise 'Request file exceeds 64 KiB.' if raw.bytesize > 65_536
  body = JSON.parse(raw)
  unless body.is_a?(Hash) && body['subject'] && (body.key?('sources') ^ body.key?('package'))
    raise 'Supply a subject and exactly one of sources or package.'
  end
  uri = URI('https://www.sanctionskit.com/api/v1/screenings')
  request = Net::HTTP::Post.new(uri)
  request['Authorization'] = "Bearer #{key}"
  request['Content-Type'] = 'application/json'
  request['Idempotency-Key'] = operation
  request.body = JSON.generate(body)
  payload = +''
  status = 0
  Net::HTTP.start(uri.host, uri.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_PEER,
                  open_timeout: 10, read_timeout: 25, write_timeout: 25) do |http|
    http.max_retries = 0
    http.request(request) do |response|
      status = response.code.to_i
      response.read_body do |chunk|
        raise 'Response size limit exceeded.' if payload.bytesize + chunk.bytesize > 8 * 1024 * 1024
        payload << chunk
      end
    end
  end
  # Net::HTTP does not automatically follow redirects.
  envelope = JSON.parse(payload)
  raise "Screening incomplete: HTTP #{status}." unless (200...300).cover?(status)
  data = envelope.is_a?(Hash) ? envelope['data'] : nil
  unless data.is_a?(Hash) && data['id'].is_a?(String) && !data['id'].empty? &&
         %w[potential_match no_match].include?(data['status']) && data['matches'].is_a?(Array)
    raise 'Incomplete response: unexpected screening shape.'
  end
  count = data['matches'].length
  if (data['status'] == 'no_match' && count != 0) || (data['status'] == 'potential_match' && count == 0)
    raise 'Incomplete response: inconsistent screening shape.'
  end
  puts JSON.generate(id: data['id'], status: data['status'], candidateCount: count)
rescue StandardError => error
  warn "Screening did not complete: #{error.class}. Check the operation before retrying."
  exit 1
end

Run the client

Run the sandbox request
ruby screen.rb request.json

Confirm OFAC scope before production

This Ruby job requests ofac-sdn. If the business requires non-SDN measures too, record that additional selection as part of the approved job definition. A customer correction and a source-policy change both need traceable new operations rather than a replay of the old body.

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

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

Interpret OFAC evidence in this workflow

Connect data.id to the queue operation and customer reference. Use data.coverage when reopening the review, because the current source catalog may have advanced after the job ran. A candidate requires evidence review; a successful worker exit does not approve the relationship.

OFAC candidate fields to retain
Fields in data.matches[]Review use
record.sourceId and record.idKeep the SDN source and stable record reference attached to the candidate.
record.designations[].programs and legalReferencesShow the listed program and legal references; do not turn every non-SDN restriction into an asset freeze.
record.names, identifiers and birthDatesCompare the supplied identity with aliases and available identifiers, preserving partial-date precision.
  • 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
  • Crash the worker after saving the result and confirm redelivery reuses the same operation.
  • Change the customer name and verify that a new operation is created.
  • Inspect job labels and logs for submitted names or bearer credentials.

Sources and references

Frequently asked questions

Does this Ruby OFAC job need a provider gem?

No. Ruby 3.1 or later provides the JSON, Net::HTTP, URI and OpenSSL libraries used here. Your queue framework still needs to manage the saved operation and distinguish a retry from a new customer check.

How should a Ruby job record a change from SDN-only coverage?

Save the revised source selection under a new screening operation. Keep the original SDN result with its prior scope so later reviewers can tell a broader check from recovery of an interrupted job.

How should a Ruby background job resume an interrupted OFAC check?

Load the existing job operation, request body, and idempotency key. A timeout can leave the result uncertain even if the server accepted it. Recover that operation first, then record its outcome before advancing the onboarding job.

What should a redelivered OFAC job do with an already saved result?

Reconcile the existing operation and retained result before issuing another request. Queue redelivery is not a reason to create another screening with a fresh key or charge the workflow for duplicate work.