Official Python SDK for the WellMarked API — convert any URL to clean Markdown.
Project description
wellmarked
Official Python SDK for the WellMarked API — convert any URL to clean Markdown.
pip install wellmarked
Quick start
from wellmarked import WellMarked
with WellMarked(api_key="wm_...") as wm:
result = wm.extract("https://example.com/article")
print(result.markdown)
print(result.metadata.title, "by", result.metadata.author)
The API key can also be picked up from the WELLMARKED_API_KEY environment variable, in which case WellMarked() is enough.
Get a key at wellmarked.io.
Pricing
| Free | Pro | Enterprise | |
|---|---|---|---|
| Price | $0 | $19/mo | $99/mo |
| Included Requests | 500/mo | 5,000/mo | 30,000/mo |
| Bulk Requests | ❌ | ✅ (up to 50/request) | ✅ (Unlimited) |
| Overage Rate | — | $0.004/req | $0.002/req |
| JS Rendering | ❌ | ✅ | ✅ |
| Priority Queue | Standard | High | Highest |
See additional pricing information at WellMarked
Async
AsyncWellMarked is a drop-in async equivalent — every endpoint method is a coroutine.
import asyncio
from wellmarked import AsyncWellMarked
async def main():
async with AsyncWellMarked() as wm:
result = await wm.extract("https://example.com/article")
print(result.markdown)
asyncio.run(main())
Bulk extraction
Submit many URLs at once (Pro: up to 50; Enterprise: unlimited). The call returns immediately with a job_id. Poll with get_job or block until done with wait_for_job.
job = wm.bulk([
"https://example.com/article-1",
"https://example.com/article-2",
])
job = wm.wait_for_job(job.job_id) # blocks until status == "done"
for item in job.results:
if item.ok:
print(item.metadata.title)
else:
print(f"{item.url} failed: {item.error}")
Usage & rate limits
get_usage() is the source of truth for your current-period quota. The quota state belongs on the account, so call get_usage() when you want it:
usage = wm.get_usage()
print(f"{usage.used} / {usage.limit} used this period ({usage.plan}) — {usage.remaining} left")
GET /usage itself does not count toward your quota.
Key rotation
rotated = wm.rotate_key()
print("New key:", rotated.api_key) # shown once — store it before the program exits
After rotate_key() the client automatically switches to the new key for subsequent calls; you still need to persist rotated.api_key somewhere durable, because the previous key stops working immediately and there is no recovery flow.
Errors
Every non-2xx response is translated into a typed exception. Catch the base class to handle anything, or the specific subclass to handle one failure mode:
from wellmarked import (
WellMarked,
AuthenticationError,
PermissionDeniedError,
NotFoundError,
UnprocessableEntityError,
RateLimitError,
APIConnectionError,
)
with WellMarked() as wm:
try:
result = wm.extract("https://example.com/paywalled")
except RateLimitError as e:
print(f"Quota hit. Resets in {e.retry_after}s.")
except UnprocessableEntityError as e:
# e.code is one of: no_content, target_timeout, js_rendering_disabled, ...
print(f"Extraction failed ({e.code}): {e.message}")
| Exception | HTTP | Typical code values |
|---|---|---|
AuthenticationError |
401 | missing_api_key, invalid_api_key |
PermissionDeniedError |
403 | account_inactive, plan_not_supported, forbidden |
NotFoundError |
404 | job_not_found |
UnprocessableEntityError |
422 | no_content, target_timeout, js_rendering_disabled, bulk_cap_exceeded |
RateLimitError |
429 | rate_limit_exceeded (carries retry_after in seconds) |
InternalServerError |
5xx | — |
APIConnectionError |
— | DNS / TCP / TLS / timeout failures, raised before any HTTP round-trip |
All inherit from WellMarkedError.
Configuration
WellMarked(
api_key="wm_...", # or set WELLMARKED_API_KEY
base_url="https://api.wellmarked.io",
timeout=30.0, # seconds, per request
http_client=my_httpx_client, # optional: bring your own httpx.Client
)
Passing your own httpx.Client/httpx.AsyncClient is useful for custom transports, proxies, or shared connection pools. When you do, the SDK won't close it on __exit__ — you remain responsible for its lifecycle.
For Agents
If you are an agent, feel free to find additional context here!
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wellmarked-1.0.0.tar.gz.
File metadata
- Download URL: wellmarked-1.0.0.tar.gz
- Upload date:
- Size: 10.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ef63f51cd87cbddcdaad1127107004370b93034f4d64be7eba00381e87d55c9
|
|
| MD5 |
9e6aaf903fa33eb0e84fdcc9e3a44c14
|
|
| BLAKE2b-256 |
a62f28ad3922b3fb79a630bb2dfcd2eaaf30582a7cbc0017707e86cde0f14f93
|
Provenance
The following attestation bundles were made for wellmarked-1.0.0.tar.gz:
Publisher:
publish-sdk.yml on gradill22/WellMarked
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wellmarked-1.0.0.tar.gz -
Subject digest:
1ef63f51cd87cbddcdaad1127107004370b93034f4d64be7eba00381e87d55c9 - Sigstore transparency entry: 1542659395
- Sigstore integration time:
-
Permalink:
gradill22/WellMarked@8c78fe82e2c0e43d1667baaa7a7067b5e79a9f5e -
Branch / Tag:
refs/tags/sdk-v1.0.0 - Owner: https://github.com/gradill22
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-sdk.yml@8c78fe82e2c0e43d1667baaa7a7067b5e79a9f5e -
Trigger Event:
release
-
Statement type:
File details
Details for the file wellmarked-1.0.0-py3-none-any.whl.
File metadata
- Download URL: wellmarked-1.0.0-py3-none-any.whl
- Upload date:
- Size: 14.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2b757e81e7d09cb536d101745273cee566f7d6609f19951ab1e23dc25631f13
|
|
| MD5 |
48c13c939ed3d81453226be6ace9d1af
|
|
| BLAKE2b-256 |
fe8dbbde6b635c8ba7e47024b242fac45cd8784522a4c9bd6ada49a379b2b965
|
Provenance
The following attestation bundles were made for wellmarked-1.0.0-py3-none-any.whl:
Publisher:
publish-sdk.yml on gradill22/WellMarked
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wellmarked-1.0.0-py3-none-any.whl -
Subject digest:
a2b757e81e7d09cb536d101745273cee566f7d6609f19951ab1e23dc25631f13 - Sigstore transparency entry: 1542659501
- Sigstore integration time:
-
Permalink:
gradill22/WellMarked@8c78fe82e2c0e43d1667baaa7a7067b5e79a9f5e -
Branch / Tag:
refs/tags/sdk-v1.0.0 - Owner: https://github.com/gradill22
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-sdk.yml@8c78fe82e2c0e43d1667baaa7a7067b5e79a9f5e -
Trigger Event:
release
-
Statement type: