Skip to content

Commit a6fe5a0

Browse files
gerwyn-ngclaude
andcommitted
Add batch_analysis POST endpoint support (v0.3.0)
- Add batch_analysis() method for the Batch Analysis POST endpoint - Add BatchAnalysisRequest, BatchAnalysisTarget, BatchAnalysisData types - Add POST request support in both sync and async clients - Bump version to 0.3.0 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 4d5b4f4 commit a6fe5a0

9 files changed

Lines changed: 486 additions & 34 deletions

File tree

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
77

88
## [Unreleased]
99

10+
## [0.3.0]
11+
12+
### Added
13+
14+
- `batch_analysis()` method for the Batch Analysis POST endpoint
15+
- `BatchAnalysisRequest`, `BatchAnalysisTarget`, `BatchAnalysisData` types
16+
- POST request support in both sync and async clients (`http_method` parameter on `_request()`)
17+
- Codegen support for POST endpoints with JSON request bodies and `$ref` resolution
18+
1019
## [0.2.0]
1120

1221
### Changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,10 @@ Or call `.close()` manually when done.
268268
See the [full API reference](docs/api-reference.md) for parameters, types, and response fields.
269269

270270
<!-- METHOD_INDEX_START -->
271+
**Batch Analysis** (1 method)
272+
273+
- `batch_analysis()`
274+
271275
**Brand Radar** (6 methods)
272276

273277
- `brand_radar_ai_responses()`
@@ -296,7 +300,7 @@ See the [full API reference](docs/api-reference.md) for parameters, types, and r
296300

297301
**Serp Overview** (1 method)
298302

299-
- `serp_overview_serp_overview()`
303+
- `serp_overview()`
300304

301305
**Site Audit** (4 methods)
302306

docs/api-reference.md

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,69 @@ For filter expression syntax (`where` parameter), see [Filter Syntax](filter-syn
1111

1212
---
1313

14+
## Batch Analysis
15+
16+
### `batch_analysis()`
17+
18+
Batch Analysis.
19+
20+
**Parameters:**
21+
22+
| Name | Type | Required | Description |
23+
|------|------|----------|-------------|
24+
| `select` | `list[str]` | Yes | A list of columns to return. See response schema for valid column identifiers. |
25+
| `order_by` | `str` | No | |
26+
| `country` | `CountryEnum` | No | A two-letter country code (ISO 3166-1 alpha-2). |
27+
| `volume_mode` | `VolumeModeEnum` | No | The search volume calculation mode: monthly or average. It affects volume, traffic, and traffic value. |
28+
| `targets` | `list[BatchAnalysisTarget]` | Yes | A list of targets to do batch analysis. |
29+
30+
**Returns:** `list[BatchAnalysisData]`
31+
32+
<details>
33+
<summary>35 fields</summary>
34+
35+
| Field | Type | Description |
36+
|-------|------|-------------|
37+
| `ahrefs_rank` | `int \| None` | The strength of your target's backlink profile compared to the other websites in our database, with rank #1 being the strongest. |
38+
| `backlinks` | `int \| None` | The total number of links from other websites pointing to your target. |
39+
| `backlinks_dofollow` | `int \| None` | Links to your target that do not contain a “nofollow”, “ugc”, or “sponsored” value in their “rel” attribute. These links are also called “dofollow”. |
40+
| `backlinks_internal` | `int \| None` | The total number of internal links pointing to the target's pages. |
41+
| `backlinks_nofollow` | `int \| None` | Links to your target that contain a “nofollow”, “ugc”, or “sponsored” value in their “rel” attribute. |
42+
| `backlinks_redirect` | `int \| None` | Links pointing to your target via a redirect. |
43+
| `domain_rating` | `float \| None` | The strength of your target's backlink profile compared to the other websites in our database on a 100-point logarithmic scale. |
44+
| `index` | `int` | Target index number. |
45+
| `ip` | `str \| None` | The IP address of the target. |
46+
| `linked_domains` | `int \| None` | The number of unique domains linked from your target. |
47+
| `linked_domains_dofollow` | `int \| None` | The number of unique domains linked from your target with followed links. |
48+
| `mode` | `str` | The target mode used for the analysis. Depending on the selected mode (Exact URL, Path, Domain, Subdomains), different parts of the website will be analyzed. |
49+
| `org_cost` | `int \| None` | (10 units) The estimated value of your target’s monthly organic search traffic. |
50+
| `org_keywords` | `int \| None` | The total number of keywords that your target ranks for in the top 100 organic search results. When ranking for the same keyword across different locations in “All locations” mode, it's still counted as one keyword. |
51+
| `org_keywords_11_20` | `int \| None` | The total number of unique keywords for which your target's top organic ranking position is within the 11th to 20th results. When ranking for the same keyword across different locations in “All locations” mode, it's still counted as one keyword. |
52+
| `org_keywords_1_3` | `int \| None` | The total number of unique keywords for which your target's top organic ranking position is within the top 3 results. When ranking for the same keyword across different locations in “All locations” mode, it's still counted as one keyword. |
53+
| `org_keywords_21_50` | `int \| None` | The total number of unique keywords for which your target's top organic ranking position is within the 21st to 50th results. When ranking for the same keyword across different locations in “All locations” mode, it's still counted as one keyword. |
54+
| `org_keywords_4_10` | `int \| None` | The total number of unique keywords for which your target's top organic ranking position is within the 4th to 10th results. When ranking for the same keyword across different locations in “All locations” mode, it's still counted as one keyword. |
55+
| `org_keywords_51_plus` | `int \| None` | The total number of unique keywords for which your target's top organic ranking position is the 51st result or higher. When ranking for the same keyword across different locations in “All locations” mode, it's still counted as one keyword. |
56+
| `org_traffic` | `int \| None` | (10 units) The estimated number of monthly visits that your target gets from organic search. |
57+
| `org_traffic_top_by_country` | `list[list[Any] \| None]` | (10 units) Top countries by traffic with corresponding traffic values. (Currently only a single element is being returned with the country with the most traffic.) |
58+
| `outgoing_links` | `int \| None` | The total number of links from your target to other domains. |
59+
| `outgoing_links_dofollow` | `int \| None` | The total number of followed links from your target to other domains. |
60+
| `paid_ads` | `int \| None` | The total number of unique ads of a target website or URL in paid search results. |
61+
| `paid_cost` | `int \| None` | (10 units) The estimated cost of your target’s monthly paid search traffic. |
62+
| `paid_keywords` | `int \| None` | The total number of keywords that your target ranks for in paid search results. When ranking for the same keyword across different locations in “All locations” mode, it's still counted as one keyword. |
63+
| `paid_traffic` | `int \| None` | (10 units) The estimated number of monthly visits that your target gets from paid search. |
64+
| `protocol` | `str` | The protocol of the target. Possible values: `both`, `http`, `https`. |
65+
| `refdomains` | `int \| None` | (5 units) The total number of unique domains linking to your target. |
66+
| `refdomains_dofollow` | `int \| None` | (5 units) The number of unique domains with links to your target that do not contain a “nofollow”, “ugc”, or “sponsored” value in their “rel” attribute. These links are also called “dofollow”. |
67+
| `refdomains_nofollow` | `int \| None` | (5 units) The number of unique domains that only have links to your target containing a “nofollow”, “ugc”, or “sponsored” value in their “rel” attribute. |
68+
| `refips` | `int \| None` | The number of unique IP addresses with at least one domain pointing to your target. Several domains can share one IP address. |
69+
| `refips_subnets` | `int \| None` | The number of c-class IP networks (AAA.BBB.CCC.DDD) with at least one link to your target. Example: 151.80.39.61 is the website IP address where 151.80.39.XXX is the subnet. |
70+
| `url` | `str` | The URL of the analyzed target. |
71+
| `url_rating` | `float \| None` | URL Rating (UR) shows the strength of your target page's backlink profile on a 100-point logarithmic scale. If you analyze a domain, the homepage's UR is shown. |
72+
73+
</details>
74+
75+
---
76+
1477
## Brand Radar
1578

1679
### `brand_radar_ai_responses()`
@@ -886,7 +949,7 @@ SERP Overview.
886949

887950
## Serp Overview
888951

889-
### `serp_overview_serp_overview()`
952+
### `serp_overview()`
890953

891954
SERP Overview.
892955

@@ -900,7 +963,7 @@ SERP Overview.
900963
| `country` | `CountryEnum` | Yes | A two-letter country code (ISO 3166-1 alpha-2). |
901964
| `keyword` | `str` | Yes | The keyword to return SERP Overview for. |
902965

903-
**Returns:** `list[SerpOverviewSerpOverviewData]`
966+
**Returns:** `list[SerpOverviewData]`
904967

905968
| Field | Type | Description |
906969
|-------|------|-------------|

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "ahrefs-python"
3-
version = "0.2.0"
3+
version = "0.3.0"
44
description = "Python client for the Ahrefs API"
55
readme = "README.md"
66
license = "MIT"

src/ahrefs/_client.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ async def _request(
6565
response_model_class: type[T],
6666
*,
6767
exclude_none: bool = False,
68+
http_method: str = "GET",
6869
) -> T:
6970
"""Make a typed API request. Called by generated endpoint methods."""
7071
url = build_url(self._config.base_url, api_section, endpoint)
@@ -82,11 +83,18 @@ async def _request(
8283
delay = calculate_backoff(attempt - 1)
8384
await asyncio.sleep(delay)
8485
try:
85-
response = await self._client.get(
86-
url,
87-
params=params,
88-
headers=build_headers(self._config.api_key),
89-
)
86+
if http_method == "POST":
87+
response = await self._client.post(
88+
url,
89+
json=params,
90+
headers=build_headers(self._config.api_key),
91+
)
92+
else:
93+
response = await self._client.get(
94+
url,
95+
params=params,
96+
headers=build_headers(self._config.api_key),
97+
)
9098
raise_for_status(response)
9199
return response_model_class.model_validate(response.json())
92100
except RateLimitError as exc:

0 commit comments

Comments
 (0)