Official Python client for Surmado's AI visibility testing and SEO reports.
One-time reports. No subscriptions. API-first.
pip install surmadofrom surmado import Surmado
client = Surmado() # uses SURMADO_API_KEY env var
# Run an AI Visibility Test
report = client.signal(
url="https://example.com",
brand_name="Example Brand",
email="you@example.com",
industry="E-commerce",
location="United States",
persona="Small business owners looking for affordable solutions",
pain_points="Finding reliable vendors, managing costs",
brand_details="Affordable solutions for growing businesses",
direct_competitors="Competitor A, Competitor B"
)
print(f"Report queued: {report['report_id']}")
# Wait for completion (or use webhooks)
completed = client.wait_for_report(report["report_id"])
print(f"PDF ready: {completed['download_url']}")
print("(Save for Surmado Solutions) Report Token: ", completed['token'])See examples/ for runnable scripts.
/client ← SDK client code (surmado package)
/examples ← Runnable usage examples
/integrations ← Integration guides (Zapier, Make, n8n, Webhooks)
README.md ← You are here
| Directory | Contents |
|---|---|
| client/ | Python package source (surmado/), unit tests |
| examples/ | Quick start script, ready to run with your API key |
| integrations/ | Step-by-step guides for Zapier, Make, n8n, and webhook setup |
| Method | Description | Credits |
|---|---|---|
client.signal(...) |
AI Visibility report — tests your brand across 7 AI platforms | 1 |
client.scan(...) |
Site Audit — comprehensive SEO analysis | 1 |
client.solutions(...) |
Strategy — multi-AI strategic recommendations from 6 agents | 1 |
client.bundle(...) |
Full Analysis — all 3 reports in one call | 3 |
result = client.signal(
url="https://acme.com",
brand_name="Acme Corp", # max 100 chars
email="you@acme.com",
industry="B2B SaaS", # max 200 chars
location="United States", # max 200 chars
persona="CTOs at mid-market companies", # max 800 chars
pain_points="Integration challenges, lack of visibility", # max 1000 chars
brand_details="Modern, dev-focused tooling", # max 1200 chars
direct_competitors="Asana, Monday.com", # max 500 chars
)result = client.scan(
url="https://acme.com",
brand_name="Acme Corp",
email="you@acme.com",
competitor_urls=["https://competitor1.com", "https://competitor2.com"]
)Mode 1: With Signal Token (recommended)
signal_result = client.signal(...)
solutions_result = client.solutions(
email="you@acme.com",
signal_token=signal_result["token"]
)result = client.solutions(
email="you@acme.com",
brand_name="Acme Corp",
business_story="We're a B2B SaaS company in project management...",
decision="Should we expand to enterprise market?",
success="$10M ARR in 18 months",
timeline="Q2 2025",
scale_indicator="$2M ARR, 20 employees"
)result = client.solutions(
email="you@acme.com",
signal_token=signal_result["token"],
include_financial=True,
financial_context="Growing but need to optimize costs",
monthly_revenue="$50K",
monthly_costs="$40K",
cash_available="$200K"
)result = client.bundle(
brand_slug="acme_corp",
email="you@acme.com"
)
# Creates Scan + Signal + Solutions in one call (3 credits)Once you've set up a brand with personas in the Surmado dashboard, run reports with minimal code:
# Signal: 3 fields instead of 10+
result = client.signal_rerun(
brand_slug="acme_corp",
persona_slug="cto-enterprise",
email="you@acme.com"
)
# Scan: 2 fields
result = client.scan_rerun(
brand_slug="acme_corp",
email="you@acme.com"
)Perfect for Zapier/Make/n8n workflows, scheduled monitoring, and dashboard integrations. See integrations/ for setup guides.
# List all brands
brands = client.list_brands()
# Create a brand (fails if already exists)
brand = client.create_brand(
brand_name="Acme Corp",
website="https://acme.com",
industry="B2B SaaS"
)
# Create or get existing brand (never fails with conflict)
brand = client.ensure_brand(
brand_name="Acme Corp",
website="https://acme.com"
)All reports process asynchronously (~15 minutes). Two ways to get results:
report = client.signal(...)
# Block until complete (default 20 min timeout)
completed = client.wait_for_report(report["report_id"], timeout_minutes=20)
print(completed["download_url"])report = client.signal(
...,
webhook_url="https://your-server.com/webhook"
)
# Your webhook receives POST with full report data when completeSee integrations/webhooks.md for payload format and handler examples.
Access raw report data (metrics, analysis) as JSON:
# Full data
data = client.get_report_data("rpt_abc123")
# Specific fields only
data = client.get_report_data("rpt_abc123", fields=["status", "insights"])from surmado import (
Surmado,
AuthenticationError,
InsufficientCreditsError,
NotFoundError,
ValidationError,
RateLimitError,
SurmadoError
)
client = Surmado()
try:
result = client.signal(...)
except AuthenticationError:
print("Invalid or missing API key")
except InsufficientCreditsError as e:
print(f"Not enough credits: {e.response}")
except RateLimitError:
print("Too many requests - back off and retry")
except NotFoundError:
print("Brand or report not found")
except ValidationError as e:
print(f"Invalid request params: {e}")
except SurmadoError as e:
print(f"API error: {e.status_code} - {e}")| Status Code | Exception |
|---|---|
| 400 | ValidationError |
| 401 | AuthenticationError |
| 402 | InsufficientCreditsError |
| 404 | NotFoundError |
| 422 | ValidationError |
| 429 | RateLimitError |
| >=500 | SurmadoError |
All exceptions inherit from SurmadoError and include status_code and response attributes.
result = client.test_auth()
print(f"Authenticated as: {result.get('org_id')}")Default request timeout is 30 seconds. Configure per-client:
client = Surmado(timeout=60)For wait_for_report, the polling timeout is separate:
completed = client.wait_for_report(report_id, timeout_minutes=30)Report creation returns HTTP 202 Accepted:
{
"report_id": "rpt_abc123def456",
"token": "tok_xyz789abc123", # Save for Solutions Mode 1
"org_id": "org_xyz789",
"product": "signal",
"status": "queued",
"brand_slug": "example_brand",
"brand_name": "Example Brand",
"credits_used": 1,
"created_at": "2025-01-15T10:30:00Z"
}Completed reports include download URLs (expire in 15 minutes):
{
"status": "completed",
"download_url": "https://storage.googleapis.com/...", # PDF
"pptx_download_url": "https://storage.googleapis.com/...", # PPTX
}See integrations/webhooks.md for the full webhook payload reference, including field tables for Signal and Scan summary data.
| Field | Max Length |
|---|---|
| brand_name | 100 chars |
| industry | 200 chars |
| location | 200 chars |
| persona | 800 chars |
| pain_points | 1000 chars |
| brand_details | 1200 chars |
| direct_competitors | 500 chars |
| indirect_competitors | 500 chars |
| keywords | 500 chars |
| product | 1000 chars |
| business_story | 2000 chars |
| decision | 1500 chars |
| success | 1000 chars |
| timeline | 200 chars |
| scale_indicator | 100 chars |
All reports are $50 each. No subscriptions.
| Product | Price | Credits |
|---|---|---|
| Signal | $50 | 1 |
| Scan | $50 | 1 |
| Solutions | $50 | 1 |
This package follows SemVer. To check your installed version:
import surmado
print(surmado.__version__)- Docs: help.surmado.com/docs/api-reference
- API Key: surmado.com/login
- Client Source: client/
- Examples: examples/
- Integrations: integrations/
- Issues: github.com/surmado/surmado-python/issues
MIT