Use this file to discover all available pages before exploring further.
For LLM agents: documentation index at /llms.txt, full text at /llms-full.txt. Append .md to any page URL for plain markdown.
AnomalyArmor ships official SDKs for Python and TypeScript. Both talk to the same REST API (app.anomalyarmor.ai) with the same aa_live_* Bearer tokens, so an existing Python script and a new Vercel function see identical data.
The Python SDK also ships the anomalyarmor CLI. The TS SDK ships an npx anomalyarmor CLI. Both CLIs read ANOMALYARMOR_API_KEY from env as a convenience - library code in both SDKs requires the key to be passed explicitly.
from anomalyarmor import Clientclient = Client( api_key="aa_live_xxx", # Or use ARMOR_API_KEY env var api_url="https://...", # Custom API URL (optional) timeout=30, # Request timeout in seconds)
from anomalyarmor import Clientfrom anomalyarmor.exceptions import StalenessErrordef check_upstream_freshness(): client = Client() try: # Raises StalenessError if stale client.freshness.require_fresh("snowflake.prod.warehouse.orders") print("Data is fresh, proceeding...") except StalenessError as e: print(f"Data is stale: {e}") raise # Fail the task
from anomalyarmor import Clientclient = Client()# All Snowflake tablestables = client.assets.list(source="snowflake", type="table")# Paginate through all assetsoffset = 0while True: assets = client.assets.list(limit=100, offset=offset) if not assets: break for asset in assets: process(asset) offset += 100
from anomalyarmor import Clientclient = Client()# Get upstream dependencieslineage = client.lineage.get("snowflake.prod.warehouse.orders")# Check all upstream sources are freshfor upstream in lineage.upstream: client.freshness.require_fresh(upstream.qualified_name)print("All upstream sources are fresh!")
from anomalyarmor import Clientclient = Client()asset_id = "550e8400-e29b-41d4-a716-446655440000"# Create a row count metric with anomaly detectionmetric = client.metrics.create( asset_id, metric_type="row_count", table_path="snowflake.prod.warehouse.orders", capture_interval="daily", sensitivity=2.0, # Alert on 2+ standard deviations)# Get metrics summarysummary = client.metrics.summary(asset_id)print(f"Health: {summary.health_percentage}%")# Check for recent anomaliessnapshots = client.metrics.snapshots(asset_id, metric.id, limit=7)anomalies = [s for s in snapshots if s.is_anomaly]if anomalies: print(f"Found {len(anomalies)} anomalies in the last 7 days")
from anomalyarmor import Clientfrom anomalyarmor.exceptions import ( StalenessError, # Data is stale AuthenticationError, # Invalid/missing API key NotFoundError, # Asset not found RateLimitError, # Rate limit exceeded ValidationError, # Invalid parameters ServerError, # Server error ArmorError, # Base exception)client = Client()try: client.freshness.require_fresh("snowflake.prod.warehouse.orders")except StalenessError as e: print(f"Data is stale: last updated {e.last_updated}")except AuthenticationError: print("Invalid API key")except RateLimitError as e: print(f"Rate limited, retry after {e.retry_after} seconds")except ArmorError as e: print(f"API error: {e}")
from anomalyarmor import Clientfrom anomalyarmor.models import Asset, FreshnessStatusclient = Client()asset: Asset = client.assets.get("snowflake.prod.warehouse.orders")status: FreshnessStatus = client.freshness.get(asset.qualified_name)print(status.is_fresh) # IDE knows this is boolprint(status.last_updated) # IDE knows this is datetime
Should I use the Python SDK or the TypeScript SDK?
Pick whichever matches the runtime you’re already using: Python for Airflow, dbt hooks, and notebooks; TypeScript for Next.js, Vercel functions, and Node services. Both SDKs wrap the same REST API and accept the same aa_live_* keys, so mixing them across services is fine. See the TypeScript SDK page for Node-specific setup.
Python 3.9 or higher. The SDK ships fully typed models (Asset, FreshnessStatus, etc.) so you get IDE completion on every method and field. Install with pip install anomalyarmor-cli, which also installs the armor CLI.
How do I paginate through thousands of assets in Python?
Call client.assets.list(limit=100, offset=n) in a loop, incrementing offset by the page size until an empty page comes back. The SDK mirrors the REST pagination directly rather than hiding it, which keeps memory flat for very large accounts. The pattern is shown in the “List and Filter Assets” example above.
Call client.freshness.require_fresh(asset) at the top of a task; it raises StalenessError when the asset is stale, which Airflow surfaces as a task failure. Set ARMOR_API_KEY as an Airflow connection secret and instantiate Client() with no arguments. The Airflow integration guide shows a full DAG.