Python SDK

Official Python SDK for OutScope API - Complete security monitoring, asset inventory, and report generation.

Version: 0.3.0 | Coverage: 61% API | Resources: 6 | Methods: 38

Features

  • Asset Inventory - Complete lifecycle management of monitored services
  • Automated Scheduling - Recurring checks (hourly, daily, weekly)
  • Security Checks - Manual and automated endpoint monitoring
  • Multi-Tenant - Company-based organization
  • Report Generation - Customizable PDF/HTML reports
  • Worker Pools - Select execution environment
  • Batch Operations - Automatic rate limit handling

Installation

pip install outscope-sdk

Or from source:

git clone https://github.com/outscope-io/outscope-sdk
cd outscope-sdk
pip install -e .

Quick Start

from outscope_sdk import Client

# Initialize client
client = Client(api_key="your_api_key_here")

# Create asset in inventory
asset = client.assets.create(
    target="api.example.com",
    name="Production API",
    tags=["production", "critical"]
)

# Set up automated daily checks
client.assets.set_schedule(asset['asset_id'], schedule="daily")

# Or run manual check
check = client.checks.create(
    fqdn="example.com",
    paths=["/", "/api"],
    ports=[443]
)

# Monitor usage
usage = client.usage.get()
print(f"Checks: {usage['usage']['checks_used']}/{usage['usage']['checks_limit']}")

client.close()

Authentication

Generate an API key from your OutScope dashboard under Settings > API Keys.

from outscope_sdk import Client
import os

# Recommended: use environment variable
client = Client(api_key=os.getenv("OUTSCOPE_API_KEY"))

# With context manager (auto-cleanup)
with Client(api_key=os.getenv("OUTSCOPE_API_KEY")) as client:
    # Your code here
    pass

Asset Inventory Management

Create Asset

# Basic asset
asset = client.assets.create(
    target="api.example.com",
    name="Production API"
)

# Full configuration
asset = client.assets.create(
    target="api.example.com",
    company_id="company_123",
    name="Production API Server",
    description="Main REST API backend",
    tags=["production", "api", "critical"],
    metadata={
        "environment": "production",
        "owner": "platform-team",
        "sla": "99.9%"
    }
)

List Assets

# All assets
assets = client.assets.list(active_only=True)

# With filters
critical_assets = client.assets.list(
    tags="critical",
    search="api",
    analyzability="analyzable",
    company_id="company_123",
    page=1,
    per_page=50
)

for asset in assets['assets']:
    print(f"{asset['name']}: {asset['target']}")

Automated Scheduling

# Set recurring checks
client.assets.set_schedule(
    asset_id=asset['asset_id'],
    schedule="daily"  # Options: none, hourly, daily, weekly
)

# Trigger manual check
check = client.assets.trigger_check(asset['asset_id'])
print(f"Check started: {check['job_id']}")

Asset Analytics

# Inventory statistics
stats = client.assets.get_stats()
print(f"Total assets: {stats['total_assets']}")
print(f"Recent checks (24h): {stats['recent_checks']}")

# Check history for asset
history = client.assets.get_checks(
    asset_id=asset['asset_id'],
    page=1,
    limit=20
)

Update & Delete

# Update asset
client.assets.update(
    asset_id=asset['asset_id'],
    name="Updated API Name",
    tags=["production", "api", "updated"]
)

# Soft delete (keeps history)
client.assets.delete(asset['asset_id'])

Security Checks

Create Check

# Basic check
check = client.checks.create(
    fqdn="example.com",
    paths=["/"],
    ports=[443]
)

# Advanced options
check = client.checks.create(
    fqdn="api.example.com",
    paths=["/", "/api/v1", "/health"],
    ports=[80, 443, 8080],
    max_redirects=1,
    collect_content_sample=True,
    content_sample_retention_days=7,
    pool_id="premium",
    company_id="company_123"
)

Batch Operations

# Create multiple checks
result = client.checks.create_batch(
    domains=["site1.com", "site2.com", "site3.com"],
    paths=["/"],
    ports=[443],
    company_id="company_123",
    check_usage_first=True,
    wait_on_limits=True,
    max_retries=5,
    progress_callback=lambda cur, tot, stats: print(f"{cur}/{tot}")
)

print(f"Created: {result['stats']['created']}")
print(f"Failed: {result['stats']['failed']}")
print(f"Duration: {result['duration']:.1f}s")

Check Status & Results

# Get check
check = client.checks.get("check_id_here")

if check['status'] == 'done':
    print(f"Analyzable: {check['result']['analysis']['analyzable']}")
    print(f"Service type: {check['result']['analysis']['kind']}")

# Latest check for domain
latest = client.checks.latest(fqdn="example.com")

# Cancel running check
client.checks.cancel(check_id="check_123")

Advanced Filtering

# Filter by multiple criteria
checks = client.checks.list(
    company_id="company_123",
    analyzability="not_analyzable",
    category="Security Blocks",
    reasons="blocked_by_security,no_http_response",
    page=1,
    limit=50
)

# Auto-pagination
for check in client.checks.list_all(analyzability="analyzable"):
    print(f"{check['fqdn_normalized']}: ready for DAST")

Review Requests

# Submit false positive review
client.checks.send_review(
    check_id="check_123",
    reason="false_positive",
    comments="This endpoint should be marked as analyzable"
)

# Check review status
status = client.checks.get_review_status(check_id="check_123")
if status['has_pending_review']:
    print("Review pending with support team")

Multi-Tenant Organization

Companies

# Create company
company = client.companies.create(name="ACME Corp")

# List companies
companies = client.companies.list(active_only=True)

# Get company
company = client.companies.get(company_id="company_123")

# Update
client.companies.update(
    company_id="company_123",
    name="ACME Corporation",
    active=True
)

# Delete
client.companies.delete(company_id="company_123")

Organize by Company

# Create asset for company
asset = client.assets.create(
    target="acme-api.com",
    company_id=company.id,
    name="ACME API"
)

# Create check for company
check = client.checks.create(
    fqdn="acme.com",
    company_id=company.id
)

# List company assets
assets = client.assets.list(company_id=company.id)

# List company checks
checks = client.checks.list(company_id=company.id)

Report Generation

Create Template

template = client.reports.create_template(
    name="Security Assessment Report",
    description="Comprehensive security report",
    branding={
        "company_name": "ACME Security",
        "primary_color": "#0066cc",
        "secondary_color": "#00cc66"
    },
    sections=[
        {"type": "executive_summary", "enabled": True},
        {"type": "security_findings", "enabled": True},
        {"type": "recommendations", "enabled": True}
    ],
    output_format="pdf"
)
logo = client.reports.upload_logo("path/to/logo.png")
# Returns: {'logo_url': '/v1/reports/logos/...'}

# Update template with logo
client.reports.update_template(
    template_id=template['template']['id'],
    branding={
        "company_name": "ACME",
        "logo_url": logo['logo_url'],
        "primary_color": "#0066cc"
    }
)

Generate Report

# Start report generation
report = client.reports.generate(
    template_id=template['template']['id'],
    title="Monthly Security Assessment",
    description="Q1 2026 Report",
    filters={
        "analyzability": "not_analyzable",
        "date_range": "last_30_days",
        "category": "Security Blocks"
    },
    company_id="company_123"
)

# Poll for completion
import time
while True:
    status = client.reports.get(report['report_id'])
    if status['report']['status'] == 'completed':
        break
    time.sleep(5)

# Download report
client.reports.download(
    report['report_id'],
    "security_assessment.pdf"
)

Worker Pools

# List available pools
pools = client.pools.list()

for pool in pools['pools']:
    print(f"{pool.display_name} ({pool.type})")
    print(f"  Available: {pool.available}")

# Use specific pool for check
check = client.checks.create(
    fqdn="critical-service.com",
    pool_id="premium-pool"  # Premium/faster execution
)

# Use pool in batch
result = client.checks.create_batch(
    domains=["site1.com", "site2.com"],
    pool_id="premium-pool"
)

Usage Monitoring

usage = client.usage.get()

# Tenant information
print(f"Tenant: {usage['tenant']['name']}")
print(f"Plan: {usage['tenant']['plan']}")

# Current usage
print(f"Checks: {usage['usage']['checks_used']}/{usage['usage']['checks_limit']}")
print(f"In progress: {usage['usage']['inflight']}/{usage['limits']['max_inflight']}")

# Limits
print(f"Rate: {usage['limits']['rate_per_minute']}/min")
print(f"Retention: {usage['limits']['retention_days']} days")

# Check quota
remaining = usage['usage']['checks_limit'] - usage['usage']['checks_used']
if remaining < 100:
    print(f"⚠️ Only {remaining} checks remaining this month")

Error Handling

from outscope_sdk.exceptions import (
    RateLimitError,
    AuthenticationError,
    NotFoundError,
    ValidationError
)

try:
    check = client.checks.create(fqdn="example.com", ports=[443])
    
except RateLimitError as e:
    if e.code == "rate_limit_exceeded":
        print(f"Rate limited: {e.limit}/min")
        print(f"Retry in {e.retry_after} seconds")
        time.sleep(e.retry_after)
    elif e.code == "inflight_limit":
        print(f"Too many concurrent checks: {e.current}/{e.limit}")
    elif e.code == "checks_limit":
        print(f"Monthly quota exceeded: {e.used}/{e.limit}")
        
except AuthenticationError as e:
    print(f"Authentication failed: {e.message}")
    
except NotFoundError as e:
    print(f"Resource not found: {e.message}")
    
except ValidationError as e:
    print(f"Invalid request: {e.message}")

Complete Workflow Example

from outscope_sdk import Client
import os
import time

# Initialize
with Client(api_key=os.getenv("OUTSCOPE_API_KEY")) as client:
    
    # 1. Create company
    company = client.companies.create(name="Production Services")
    
    # 2. Add assets to inventory
    assets = []
    for target in ["api.example.com", "app.example.com", "admin.example.com"]:
        asset = client.assets.create(
            target=target,
            company_id=company.id,
            tags=["production"]
        )
        assets.append(asset)
    
    # 3. Set up automated monitoring
    for asset in assets:
        client.assets.set_schedule(
            asset['asset_id'],
            schedule="daily"
        )
    
    # 4. Trigger immediate checks
    checks = []
    for asset in assets:
        check = client.assets.trigger_check(asset['asset_id'])
        checks.append(check)
    
    # 5. Wait for completion
    print("Waiting for checks to complete...")
    time.sleep(30)
    
    # 6. Generate report
    template = client.reports.create_template(
        name="Production Report",
        company_id=company.id
    )
    
    report = client.reports.generate(
        template_id=template['template']['id'],
        title="Production Security Assessment",
        company_id=company.id
    )
    
    # 7. Check usage
    usage = client.usage.get()
    print(f"Checks used: {usage['usage']['checks_used']}/{usage['usage']['checks_limit']}")

CI/CD Integration

#!/usr/bin/env python3
import sys
import os
from outscope_sdk import Client

client = Client(api_key=os.getenv('OUTSCOPE_API_KEY'))

# Production endpoints to monitor
endpoints = [
    "api.prod.example.com",
    "app.prod.example.com",
    "admin.prod.example.com"
]

# Create checks
result = client.checks.create_batch(
    domains=endpoints,
    wait_on_limits=True,
    company_id=os.getenv('COMPANY_ID')
)

if result['stats']['failed'] > 0:
    print(f"❌ Failed to create {result['stats']['failed']} checks")
    sys.exit(1)

print(f"✅ Created {result['stats']['created']} checks successfully")
sys.exit(0)

Advanced Features

Custom Timeout

client = Client(
    api_key="your_key",
    timeout=120.0  # 2 minutes
)

Retry Configuration

# Automatic retry with exponential backoff
def create_with_retry(fqdn, max_attempts=3):
    for attempt in range(max_attempts):
        try:
            return client.checks.create(fqdn=fqdn)
        except RateLimitError as e:
            if attempt == max_attempts - 1:
                raise
            time.sleep(e.retry_after or 60)

SDK Resources Overview

ResourceMethodsDescription
Assets10Complete inventory lifecycle
Checks10Security monitoring
Companies5Multi-tenant organization
Reports11Customizable reports
Pools1Worker pool selection
Usage1Limits and usage tracking
Total3861% API Coverage

Version History

v0.3.0 (Current)

  • ✅ Assets resource - Complete inventory management
  • ✅ Automated scheduling (hourly, daily, weekly)
  • ✅ Asset lifecycle tracking
  • ✅ Check history per asset

v0.2.1

  • ✅ Reports resource - PDF/HTML generation
  • ✅ Template management
  • ✅ Logo upload

v0.2.0

  • ✅ Companies resource - Multi-tenant support
  • ✅ Worker pools - Pool selection
  • ✅ Advanced check filtering
  • ✅ Check lifecycle operations

Support & Resources

Need Help?

Can't find what you're looking for? We're here to help.