seoscoreapi 1.3.1__tar.gz → 1.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: seoscoreapi
3
- Version: 1.3.1
3
+ Version: 1.4.0
4
4
  Summary: Python client for SEO Score API — audit any URL for SEO issues with one function call
5
5
  Author-email: SEO Score API <info@seoscoreapi.com>
6
6
  License: MIT
@@ -83,6 +83,35 @@ add_monitor(
83
83
 
84
84
  Slack incoming-webhook URLs are auto-formatted as Block Kit messages; any other https endpoint receives the raw event JSON.
85
85
 
86
+ ## Deep Audits (Pro/Ultra)
87
+
88
+ A deep, AI-assisted audit scoring a URL across 9 dimensions (~150 AI checks). It
89
+ runs asynchronously — submit, then poll — or use `deep_audit` to block for the result:
90
+
91
+ ```python
92
+ import seoscoreapi as seo
93
+
94
+ # One call, waits for the result (handles the queue + backpressure for you):
95
+ result = seo.deep_audit(
96
+ "https://yoursite.com", API_KEY,
97
+ business_type="saas", # tunes which checks apply
98
+ on_progress=lambda s: print(s["status"], s.get("queue_position", s.get("progress"))),
99
+ )
100
+ print(result["scores"]["lai_score"], result["scores"]["section_scores"])
101
+
102
+ # Or drive the job yourself:
103
+ job = seo.site_audit("https://yoursite.com", API_KEY)
104
+ status = seo.get_site_audit(job["job_id"], API_KEY)
105
+ # status["status"] -> queued | running | completed | failed
106
+ # queued -> {"queue_position", "eta_seconds"}
107
+ # done -> {"result"}
108
+
109
+ seo.engine_usage(API_KEY) # remaining deep-audit + SERP quota
110
+ ```
111
+
112
+ Deep audits require a **Pro** ($39/mo, 20/mo) or **Ultra** ($99/mo, 100/mo) key.
113
+ Full engine reference: [engine.seoscoreapi.com/docs](https://engine.seoscoreapi.com/docs).
114
+
86
115
  ## Full Documentation
87
116
 
88
117
  [seoscoreapi.com/docs](https://seoscoreapi.com/docs)
@@ -65,6 +65,35 @@ add_monitor(
65
65
 
66
66
  Slack incoming-webhook URLs are auto-formatted as Block Kit messages; any other https endpoint receives the raw event JSON.
67
67
 
68
+ ## Deep Audits (Pro/Ultra)
69
+
70
+ A deep, AI-assisted audit scoring a URL across 9 dimensions (~150 AI checks). It
71
+ runs asynchronously — submit, then poll — or use `deep_audit` to block for the result:
72
+
73
+ ```python
74
+ import seoscoreapi as seo
75
+
76
+ # One call, waits for the result (handles the queue + backpressure for you):
77
+ result = seo.deep_audit(
78
+ "https://yoursite.com", API_KEY,
79
+ business_type="saas", # tunes which checks apply
80
+ on_progress=lambda s: print(s["status"], s.get("queue_position", s.get("progress"))),
81
+ )
82
+ print(result["scores"]["lai_score"], result["scores"]["section_scores"])
83
+
84
+ # Or drive the job yourself:
85
+ job = seo.site_audit("https://yoursite.com", API_KEY)
86
+ status = seo.get_site_audit(job["job_id"], API_KEY)
87
+ # status["status"] -> queued | running | completed | failed
88
+ # queued -> {"queue_position", "eta_seconds"}
89
+ # done -> {"result"}
90
+
91
+ seo.engine_usage(API_KEY) # remaining deep-audit + SERP quota
92
+ ```
93
+
94
+ Deep audits require a **Pro** ($39/mo, 20/mo) or **Ultra** ($99/mo, 100/mo) key.
95
+ Full engine reference: [engine.seoscoreapi.com/docs](https://engine.seoscoreapi.com/docs).
96
+
68
97
  ## Full Documentation
69
98
 
70
99
  [seoscoreapi.com/docs](https://seoscoreapi.com/docs)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "seoscoreapi"
7
- version = "1.3.1"
7
+ version = "1.4.0"
8
8
  description = "Python client for SEO Score API — audit any URL for SEO issues with one function call"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -17,14 +17,19 @@ Usage:
17
17
  Full docs: https://seoscoreapi.com/docs
18
18
  """
19
19
 
20
- from typing import Optional
20
+ from __future__ import annotations # lazy annotations so `list[str]` works on Python 3.8
21
+
22
+ import time
23
+ from typing import Callable, Optional
21
24
 
22
25
  import requests
23
26
 
24
27
  BASE_URL = "https://seoscoreapi.com"
25
- __version__ = "1.3.1"
28
+ ENGINE_URL = "https://engine.seoscoreapi.com"
29
+ __version__ = "1.4.0"
26
30
 
27
31
  _HEADERS = {"User-Agent": f"seoscoreapi-python/{__version__}"}
32
+ _TIMEOUT = 30 # seconds — default per-request timeout for engine calls
28
33
 
29
34
 
30
35
  def signup(email: str) -> str:
@@ -130,3 +135,96 @@ def history_domains(api_key: str) -> list:
130
135
  r = requests.get(f"{BASE_URL}/history/domains", headers={"X-API-Key": api_key, **_HEADERS})
131
136
  r.raise_for_status()
132
137
  return r.json()["domains"]
138
+
139
+
140
+ # --- Deep Audits (engine.seoscoreapi.com) — Pro/Ultra -----------------------
141
+
142
+ def site_audit(url: str, api_key: str, **options) -> dict:
143
+ """Start a Deep Audit (Pro/Ultra). Asynchronous — returns a job
144
+ ``{"job_id", "status", "poll"}``; poll it with :func:`get_site_audit`.
145
+
146
+ Optional keyword args: ``business_type``, ``is_local``,
147
+ ``connected_integrations``, ``webhook_url``.
148
+ """
149
+ r = requests.post(
150
+ f"{ENGINE_URL}/site-audit",
151
+ json={"url": url, **options},
152
+ headers={"X-API-Key": api_key, **_HEADERS},
153
+ timeout=_TIMEOUT,
154
+ )
155
+ r.raise_for_status()
156
+ return r.json()
157
+
158
+
159
+ def get_site_audit(job_id: str, api_key: str) -> dict:
160
+ """Poll a deep audit job. Returns ``status`` plus ``queue_position``/
161
+ ``eta_seconds`` while queued, ``progress``/``stage`` while running, and
162
+ ``result`` when completed (or ``error`` when failed)."""
163
+ r = requests.get(
164
+ f"{ENGINE_URL}/site-audit/{job_id}",
165
+ headers={"X-API-Key": api_key, **_HEADERS},
166
+ timeout=_TIMEOUT,
167
+ )
168
+ r.raise_for_status()
169
+ return r.json()
170
+
171
+
172
+ def deep_audit(
173
+ url: str,
174
+ api_key: str,
175
+ *,
176
+ poll_interval: float = 5.0,
177
+ timeout: float = 600.0,
178
+ on_progress: Optional[Callable[[dict], None]] = None,
179
+ **options,
180
+ ) -> dict:
181
+ """Start a deep audit and block until it finishes; return the result dict.
182
+
183
+ Handles queue backpressure (429 + ``Retry-After``) and honors the server's
184
+ ETA between polls. Raises ``TimeoutError`` if it doesn't finish within
185
+ ``timeout`` seconds, or ``RuntimeError`` if the audit fails.
186
+ """
187
+ deadline = time.monotonic() + timeout
188
+ while True: # submit, retrying on backpressure
189
+ r = requests.post(
190
+ f"{ENGINE_URL}/site-audit",
191
+ json={"url": url, **options},
192
+ headers={"X-API-Key": api_key, **_HEADERS},
193
+ timeout=_TIMEOUT,
194
+ )
195
+ if r.status_code == 429:
196
+ retry = float(r.headers.get("Retry-After", 5))
197
+ if time.monotonic() + retry > deadline:
198
+ raise TimeoutError("Timed out waiting for queue capacity")
199
+ time.sleep(retry)
200
+ continue
201
+ r.raise_for_status()
202
+ job = r.json()
203
+ break
204
+
205
+ while True: # poll to completion
206
+ if time.monotonic() > deadline:
207
+ raise TimeoutError("Timed out waiting for audit to complete")
208
+ status = get_site_audit(job["job_id"], api_key)
209
+ if on_progress:
210
+ on_progress(status)
211
+ state = status.get("status")
212
+ if state == "completed":
213
+ return status["result"]
214
+ if state == "failed":
215
+ raise RuntimeError(status.get("error", "Audit failed"))
216
+ if state == "queued" and status.get("eta_seconds"):
217
+ time.sleep(min(status["eta_seconds"], 15.0))
218
+ else:
219
+ time.sleep(poll_interval)
220
+
221
+
222
+ def engine_usage(api_key: str) -> dict:
223
+ """Remaining engine quota (deep audits + SERP) for this key."""
224
+ r = requests.get(
225
+ f"{ENGINE_URL}/usage",
226
+ headers={"X-API-Key": api_key, **_HEADERS},
227
+ timeout=_TIMEOUT,
228
+ )
229
+ r.raise_for_status()
230
+ return r.json()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: seoscoreapi
3
- Version: 1.3.1
3
+ Version: 1.4.0
4
4
  Summary: Python client for SEO Score API — audit any URL for SEO issues with one function call
5
5
  Author-email: SEO Score API <info@seoscoreapi.com>
6
6
  License: MIT
@@ -83,6 +83,35 @@ add_monitor(
83
83
 
84
84
  Slack incoming-webhook URLs are auto-formatted as Block Kit messages; any other https endpoint receives the raw event JSON.
85
85
 
86
+ ## Deep Audits (Pro/Ultra)
87
+
88
+ A deep, AI-assisted audit scoring a URL across 9 dimensions (~150 AI checks). It
89
+ runs asynchronously — submit, then poll — or use `deep_audit` to block for the result:
90
+
91
+ ```python
92
+ import seoscoreapi as seo
93
+
94
+ # One call, waits for the result (handles the queue + backpressure for you):
95
+ result = seo.deep_audit(
96
+ "https://yoursite.com", API_KEY,
97
+ business_type="saas", # tunes which checks apply
98
+ on_progress=lambda s: print(s["status"], s.get("queue_position", s.get("progress"))),
99
+ )
100
+ print(result["scores"]["lai_score"], result["scores"]["section_scores"])
101
+
102
+ # Or drive the job yourself:
103
+ job = seo.site_audit("https://yoursite.com", API_KEY)
104
+ status = seo.get_site_audit(job["job_id"], API_KEY)
105
+ # status["status"] -> queued | running | completed | failed
106
+ # queued -> {"queue_position", "eta_seconds"}
107
+ # done -> {"result"}
108
+
109
+ seo.engine_usage(API_KEY) # remaining deep-audit + SERP quota
110
+ ```
111
+
112
+ Deep audits require a **Pro** ($39/mo, 20/mo) or **Ultra** ($99/mo, 100/mo) key.
113
+ Full engine reference: [engine.seoscoreapi.com/docs](https://engine.seoscoreapi.com/docs).
114
+
86
115
  ## Full Documentation
87
116
 
88
117
  [seoscoreapi.com/docs](https://seoscoreapi.com/docs)
File without changes