Python SDK Reference
Neuramancer Python SDK
Section titled “Neuramancer Python SDK”Python client for the Neuramancer fake-detection API. Every API endpoint has its own file containing a pure function you can import, or run directly as a CLI script.
Follow the Onboarding Guide to install dependencies and set up your environment before making API calls.
Verify — Run All E2E Tests
Section titled “Verify — Run All E2E Tests”Run every E2E test included in your SDK package:
bash run_all_e2e.sh| Option | Description |
|---|---|
SKIP_ANALYSIS=1 bash run_all_e2e.sh | Skip the analysis_run_e2e test (fast check) |
The script will:
- Activate the Python venv if present
- Run each
*_e2e.pytest sequentially - Print a pass / fail / skip summary at the end
- Exit with code
1if any test failed
Alternatively, you can run each individual *_e2e.py test in isolation.
CLI Usage
Section titled “CLI Usage”Every file accepts -h / --help. Output is JSON and can be piped to jq.
Make sure the venv is activated first: source venv/bin/activate
# Create an analysispython api_requests/create_analysis.py ./trial_images/fake.jpg --width 720 --height 960 | jq
# Create without upload (record only — upload separately, then start)python api_requests/create_analysis.py ./trial_images/fake.jpg --width 720 --height 960 --no-upload | jq
# <analysis_id> stands for a 24-character hex ObjectId returned by the create_analysis call like this: 65a1b2c3d4e5f6a7b8c9d0e1
# Start analysis inference (after uploading separately)python api_requests/start_analysis.py <analysis_id> | jq
# Get a single analysispython api_requests/get_analysis.py <analysis_id> | jq
# Poll until completepython api_requests/get_analysis.py <analysis_id> --poll --interval 5 --max-attempts 60 | jq
# List analysespython api_requests/list_analyses.py --search <search_term> --limit 10 | jq
# Deletepython api_requests/delete_analysis.py <analysis_id> | jq
# Retry with different optionspython api_requests/retry_analysis.py <analysis_id> --tier forensicReporting | jq
# Tenant infopython api_requests/get_tenant.py | jqpython api_requests/update_tenant.py --s3-from-env | jqpython api_requests/get_tenant_report.py range --start 2025-01-01 --end 2027-01-31 | jq
# API key managementpython api_requests/get_apikeys.py | jqpython api_requests/create_apikey.py "Production Key" 365 | jqpython api_requests/delete_apikey.py <uuid> | jq
# Health / pingpython api_requests/health.py | jqpython api_requests/ping.py | jqUsing as a Library
Section titled “Using as a Library”Import from the api_requests package to load all functions at once, or import individual modules:
# Load all request functionsfrom api_requests import create_analysis, poll_analysis
# Or import from individual modules# from api_requests.create_analysis import create_analysis# from api_requests.get_analysis import poll_analysis
# Createresult = create_analysis(True, "./image.jpg", { "width": 720, "height": 960, "tier": "forensicReporting",})analysis_id = result["data"][0]["id"]print(f"Created in {result['_meta']['durationMs']}ms")
# Poll until donefinal = poll_analysis(analysis_id, interval_sec=5, max_attempts=60)analysis = final["data"][0]print(analysis["inferenceStatus"]["result"]["decision"])See ./demo_library_usage.py for a runnable example.
Return Format
Section titled “Return Format”All SDK functions return the API response body 1:1 as a dict, with one additional key _meta containing SDK-produced runtime metadata:
{ # ---- API response body (1:1, varies by endpoint) ---- "success": True, "data": [ ... ],
# ---- SDK metadata (always present) ---- "_meta": { "durationMs": 123.45, # Wall-clock time in milliseconds "status": 200, # HTTP status code "error": None, # Always None on success }}All functions throw RuntimeError on API errors (non-2xx status codes or connection failures). Wrap calls in try/except to handle errors:
try: result = get_analysis("abc123")except RuntimeError as e: print(f"API error: {e}")create_analysis() adds extra fields to _meta when upload=True (the default):
_meta key | Type | Description |
|---|---|---|
durationMs | float | Total time (create + upload + finish) |
status | int | HTTP status of the create call |
error | None | Always None on success |
uploadResult | dict | Upload response (success, status, duration_ms, error) |
startAnalysisResult | dict | Start-analysis API response body |
API Reference
Section titled “API Reference”Analysis
Section titled “Analysis”Create Analysis — create_analysis.py
Section titled “Create Analysis — create_analysis.py”Creates an analysis, uploads an image via a presigned URL, and finalises the upload (3-step flow).
When --no-upload is passed (or upload=False in code), only step A is executed — the analysis record is created but no file is uploaded.
python create_analysis.py <image> --width <int> --height <int> \ [--format jpg|png] [--name NAME] [--comment TEXT] \ [--model MODEL] [--decision-strategy STRATEGY] \ [--tier flagging|forensicReporting] \ [--seed INT] [--no-upload]Function signature:
create_analysis(upload: bool = True, image_path: str = '', options: dict | None = None) -> dict| Parameter | Required | Default | Description |
|---|---|---|---|
upload | — | True | Whether to upload and then start the analysis |
image_path | when upload=True | '' | Path to the image file |
--width | ✔ | — | Image width in pixels (>64, ≤8192) |
--height | ✔ | — | Image height in pixels (>64, ≤8192) |
--name | — | filename | Display name for the analysis |
--format | — | auto-detect | jpg or png |
--comment | — | "" | Free-text comment |
--model | — | nais-image-latest | Inference model identifier |
--decision-strategy | — | default | default|pedantic|relaxed |
--tier | — | flagging | flagging or forensicReporting |
--seed | — | 1337 | Random seed for inference reproducibility |
--no-upload | — | — | Only create the record (skip upload + finalise) |
--tier defaults to flagging. Set --tier forensicReporting for the full forensic result set. See Cost Model.
The library function create_analysis() also accepts filename (original filename) and tags (list of strings) via the options dict.
For S3-backed analyses, the API response includes storageUrls.objectKey for the uploaded input file and generated result files. This is the exact object path in the bucket.
Example:
bucket-hash/analysis-image-697fbb59f0630-857f5013877f5dbb5cbIf you split this value at /, the last segment is the filename in object storage:
analysis-image-697fbb59f0630-857f5013877f5dbb5cbThat filename suffix is a SHA-256 hash of a random UUID. It is generated intentionally so filenames do not collide in storage. For direct bucket access, always use the full storageUrls.objectKey, not only the final filename segment.
Get Analysis — get_analysis.py
Section titled “Get Analysis — get_analysis.py”Retrieves a single analysis by ID (24-character hex ObjectId).
python get_analysis.py <analysis_id> [--poll] [--interval SECONDS] [--max-attempts N]Pass --poll to automatically poll until the analysis reaches completed or failed (default: 10 s interval, 30 max attempts). The first poll waits INITIAL_POLL_TIME_SECS (21 s) to account for p99 processing time.
List Analyses — list_analyses.py
Section titled “List Analyses — list_analyses.py”Lists analyses with optional search and pagination.
python list_analyses.py [--search TEXT] [--start INT] [--limit INT] [--tenant NAME]| Parameter | Default | Description |
|---|---|---|
--search | — | Free-text search over name and comment |
--start | 0 | Zero-based pagination offset |
--limit | 25 | Page size (≥ 1) |
--tenant | .env | Tenant name override |
Delete Analysis — delete_analysis.py
Section titled “Delete Analysis — delete_analysis.py”Soft-deletes an analysis by ID.
python delete_analysis.py <analysis_id>Retry Analysis — retry_analysis.py
Section titled “Retry Analysis — retry_analysis.py”Re-runs inference on an existing analysis, optionally with updated options.
python retry_analysis.py <analysis_id> \ [--tier flagging|forensicReporting] [--model MODEL] \ [--decision-strategy STR]Valid --decision-strategy values: default, pedantic, relaxed.
Start Analysis — start_analysis.py
Section titled “Start Analysis — start_analysis.py”Confirms an analysis upload and triggers inference (after create_analysis() was called with --no-upload).
python start_analysis.py <analysis_id> [--tenant-name NAME]Tenant
Section titled “Tenant”Get Tenant — get_tenant.py
Section titled “Get Tenant — get_tenant.py”Retrieves tenant details (storage config, masked API keys).
python get_tenant.py [TENANT_NAME]Update Tenant — update_tenant.py
Section titled “Update Tenant — update_tenant.py”Updates tenant settings. Pass --s3-from-env to populate S3 config from .env variables.
python api_requests/update_tenant.py [--s3-from-env] [KEY=VALUE ...]🚨 DANGER: This overwrites existing tenant settings. Ensure your
.envfile reflects the intended state.
Get Tenant Report — get_tenant_report.py
Section titled “Get Tenant Report — get_tenant_report.py”Retrieves a tenant usage report (total or date-range).
python get_tenant_report.py [total|range] [--start DATE] [--end DATE]API Keys
Section titled “API Keys”List API Keys — get_apikeys.py
Section titled “List API Keys — get_apikeys.py”python get_apikeys.py [TENANT_NAME]Create API Key — create_apikey.py
Section titled “Create API Key — create_apikey.py”python create_apikey.py <key_name> <expiry_in_days>⚠️ WARNING: The clear-text key is shown only once. Store it securely.
Delete API Key — delete_apikey.py
Section titled “Delete API Key — delete_apikey.py”python delete_apikey.py <uuid>Utilities
Section titled “Utilities”| Script | Description |
|---|---|
ping.py | Lightweight connectivity check (no auth required) |
health.py | Health check (no auth required) returning server uptime |
E2E Workflow Tests
Section titled “E2E Workflow Tests”The SDK ships integration tests that exercise full API workflows. They double as runnable usage examples.
| Script | Auth | Workflow |
|---|---|---|
analysis_run_e2e.py | ApiKey | Runs inference on fake.jpg (expects “fake”) and real.jpg (expects “real”), verifying classification for each. |
apikey_crud_e2e.py | ApiKey | Create a temporary API key ⇒ list & verify ⇒ delete ⇒ verify removal. |
list_analyses_e2e.py | ApiKey | List analyses ⇒ search by name ⇒ paginate. |
monitoring_e2e.py | ApiKey | Ping (no auth) ⇒ authenticated health check. |
tenant_report_e2e.py | ApiKey | Get tenant info ⇒ fetch total usage report. |
update_tenant_e2e.py | ApiKey | Read tenant ⇒ set test webhook URL ⇒ verify ⇒ restore original ⇒ verify. |
analysis_lifecycle_e2e.py | ApiKey | Full lifecycle: create (no upload) ⇒ manual upload ⇒ start ⇒ poll ⇒ get ⇒ list (search, pagination) ⇒ retry ⇒ poll ⇒ verify diff ⇒ delete ⇒ confirm 404. |
# Run a single testpython analysis_run_e2e.py
# Run all testsbash run_all_e2e.shAnalysis Tiers
Section titled “Analysis Tiers”| Tier | Description |
|---|---|
flagging (default) | Fast binary flag — returns only decision + confidence. Fields like predictions, heatmaps, pdfReportStorageUrls, text-content fields are null. |
forensicReporting | Full forensic analysis — all fields populated, PDF export available. |
Set the tier when creating an analysis:
python api_requests/create_analysis.py image.jpg --width 720 --height 960 --tier forensicReportingBenchmarking
Section titled “Benchmarking”# Run 4 parallel create-and-poll cyclesbash run_benchmark.sh 4Requires jq. See run_benchmark.sh for tuneable parameters.
