Python SDK for the Enconvert file conversion API
Project description
enconvert
Python SDK for the Enconvert file conversion API.
Convert URLs to PDFs, capture screenshots, extract Markdown, crawl whole websites, transform images, and convert documents — all with a single API call. Python 3.9+.
Install
pip install enconvert
Quick Start
from enconvert import Enconvert
client = Enconvert(api_key="sk_...")
URL to PDF
result = client.convert_url_to_pdf("https://example.com", save_to="page.pdf")
print(result.presigned_url)
URL to Screenshot
result = client.convert_url_to_screenshot(
"https://example.com",
viewport_width=1440,
save_to="screenshot.png",
)
URL to Markdown
Extract clean GitHub-Flavored Markdown from any URL — strips nav/footer/ads/scripts, keeps the main article content, and adds YAML frontmatter (title, description, url, links, images).
result = client.convert_url_to_markdown(
"https://example.com/article",
save_to="article.md",
)
Website to PDF / Screenshot (whole-site batch)
Discover every page of a website (via sitemap, or full crawl on Pro/Business plans), convert each one in the background, and receive a single ZIP. Requires a private API key with crawl access.
batch = client.convert_website_to_pdf(
"https://example.com",
crawl_mode="sitemap", # "auto" (default) | "sitemap" | "full"
exclude_patterns=["/blog/tag/"], # full crawl mode only
)
print(batch.batch_id, batch.url_count, batch.discovery_method)
# Block until done and save the ZIP:
status = client.wait_for_batch(batch.batch_id, save_to="site.zip")
print(status.completed, "of", status.total, "pages converted")
# Or poll yourself:
s = client.get_batch_status(batch.batch_id)
if s.status != "processing":
print(s.zip_download_url)
convert_website_to_screenshot works the same way and produces a ZIP of PNGs.
Image Conversion
result = client.convert_image(
"photo.heic",
output_format="webp",
save_to="photo.webp",
)
Any pair among jpeg, png, svg, heic, webp — plus PDF rasterization:
client.convert_image("scan.pdf", output_format="jpeg", save_to="scan.jpeg")
Document Conversion
client.convert_document("report.docx", save_to="report.pdf")
client.convert_document("data.json", output_format="yaml", save_to="data.yaml")
client.convert_document("notes.md", output_format="html", save_to="notes.html")
Supported inputs: doc/docx, xls/xlsx, ppt/pptx, odt, ods, odp, ots, pages, numbers, epub, html, markdown, csv, json, xml, yaml, toml
The SDK validates every {input}-to-{output} pair against the conversions the API actually implements and raises immediately — with the list of valid outputs for that input — instead of sending a doomed request. Introspect programmatically:
from enconvert import IMPLEMENTED_CONVERSIONS, valid_outputs_for
valid_outputs_for("json") # ["csv", "toml", "xml", "yaml"]
valid_outputs_for("pdf") # ["jpeg"]
Supported conversions
| Input | Outputs |
|---|---|
| json | csv, toml, xml, yaml |
| xml | csv, json |
| yaml | json |
| csv | json, xml |
| toml | json |
| markdown | html, pdf |
| html | |
| doc, excel, ppt, odt, ods, odp, ots, pages, numbers, epub | |
| jpeg, png, svg, heic, webp | each other (all 20 pairs) |
| jpeg |
Job Status (async polling)
status = client.get_job_status("job_abc123")
if status.status == "success":
print(status.presigned_url)
PDF Options
from enconvert import PdfHeaderFooter, PdfMargins, PdfOptions
result = client.convert_url_to_pdf(
"https://example.com",
pdf_options=PdfOptions(
page_size="A4", # or custom dimensions via page_width + page_height
orientation="landscape",
margins=PdfMargins(top=10, bottom=10, left=15, right=15),
header=PdfHeaderFooter(content="Quarterly Report", height=15),
footer=PdfHeaderFooter(content="Confidential", height=12),
),
save_to="report.pdf",
)
Authenticated Pages (plan-gated)
All URL and website conversions accept HTTP Basic Auth, cookies, and custom headers for pages behind a login:
from enconvert import BrowserCookie, HttpBasicAuth
client.convert_url_to_pdf(
"https://internal.example.com/report",
auth=HttpBasicAuth(username="user", password="pass"),
# or cookies / headers:
cookies=[BrowserCookie(name="session", value="abc123", domain="internal.example.com")],
headers={"X-Tenant": "acme"},
save_to="report.pdf",
)
Do not combine auth with an Authorization header — the API rejects the conflict.
Error Handling
from enconvert import Enconvert, APIError, AuthenticationError, RateLimitError
try:
client.convert_url_to_pdf("https://example.com")
except AuthenticationError:
print("Invalid API key")
except RateLimitError:
print("Too many requests — slow down")
except APIError as e:
print(f"API error [{e.status_code}]: {e.message}")
Configuration
client = Enconvert(
api_key="sk_...",
timeout=300.0, # seconds, default
base_url="https://api.enconvert.com", # default
)
V2 API (client.v2)
The V2 namespace turns web pages into agent-ready data: render, search, extract, ingest, and monitor. All V2 endpoints require a private API key and are plan-gated — a disabled feature or exhausted monthly quota raises QuotaError (HTTP 402).
Perceive — render a URL into artifacts
op = client.v2.perceive(
"https://example.com",
outputs=["markdown", "screenshot", "structured"],
extract=["tables", "metadata"],
)
print(op.outputs["markdown"].url) # 15-min signed URL
print(op.structured)
# Re-sign artifact URLs later:
again = client.v2.get_perceive_operation(op.operation_id)
# Batch (<=10 URLs runs inline; larger returns "queued" — poll):
batch = client.v2.perceive_batch(
["https://a.com", "https://b.com"],
outputs=["markdown"],
output_mode="zip",
)
done = client.v2.get_perceive_batch(batch.job_id)
Discover — enumerate a site's URLs (no rendering)
found = client.v2.discover(
"https://example.com",
mode="hybrid", # "sitemap" | "crawl" | "hybrid"
max_urls=200,
exclude_patterns=["/tag/"],
)
print(found.total, found.urls)
Lookup — web search with optional auto-perceive
search = client.v2.lookup(
"best static site generators",
category="web", # web | news | images | scholar | patents | maps
num_results=10,
perceive_top=3, # auto-render top 3 results (uses perceive quota)
)
for hit in search.results:
print(hit.title, hit.url, hit.perceive.outputs if hit.perceive else None)
Distill — schema-driven structured extraction
from enconvert import CssField, CssSchema
extraction = client.v2.distill(
urls=["https://example.com/pricing"],
schema={"plans": "list of plan names with monthly prices"},
css_schema=CssSchema( # optional free CSS pass before the LLM tier
base_selector=".plan-card",
fields=[
CssField(name="name", type="text", selector="h3"),
CssField(name="price", type="text", selector=".price"),
],
),
)
print(extraction.results[0].data, extraction.results[0].extraction_tier)
# Or discover-then-distill:
from enconvert import DistillDiscoverFrom
client.v2.distill(
discover_from=DistillDiscoverFrom(url="https://example.com", mode="sitemap", max_pages=10),
schema={"title": "page title", "summary": "one-line summary"},
)
Ingest — site to RAG-ready JSONL (always async)
from enconvert import IngestChunkOptions
job = client.v2.ingest(
mode="sitemap",
url="https://docs.example.com",
max_pages=100,
chunk=IngestChunkOptions(max_words=512, sentence_overlap=1),
webhook_url="https://my.app/hooks/enconvert",
)
status = client.v2.get_ingest_job(job.job_id) # poll
if status.status == "completed":
print(status.output_url) # JSONL
client.v2.list_ingest_jobs(limit=20)
client.v2.cancel_ingest_job(job.job_id) # idempotent
# Webhook signing (HMAC):
secret = client.v2.get_webhook_secret()
print(secret.secret, secret.signature_header)
client.v2.rotate_webhook_secret() # invalidates old secret
client.v2.retry_ingest_webhook(job.job_id) # re-deliver
Watch — recurring change monitoring
watcher = client.v2.create_watcher(
"https://example.com/pricing",
frequency_minutes=60, # hourly floor
diff_mode="auto", # auto | text | structured | tables | metadata
webhook_url="https://my.app/hooks/changes",
notify_email=True,
)
client.v2.list_watchers()
client.v2.get_watcher(watcher.watcher_id)
client.v2.get_watcher_snapshots(watcher.watcher_id, limit=10)
client.v2.update_watcher(watcher.watcher_id, status="paused")
client.v2.update_watcher(watcher.watcher_id, webhook_url="") # clears webhook
client.v2.delete_watcher(watcher.watcher_id) # soft-delete, idempotent
V2 error handling
from enconvert import QuotaError
try:
client.v2.ingest(urls=["https://example.com"])
except QuotaError:
print("Upgrade plan or wait for quota reset")
Get an API Key
Sign up at enconvert.com to get your API key.
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 enconvert-0.0.1.tar.gz.
File metadata
- Download URL: enconvert-0.0.1.tar.gz
- Upload date:
- Size: 30.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df395a41a1a8bae80a97409c87becf2443bda7fcf24cf57ddc2fc66db2aef078
|
|
| MD5 |
1e59d0541985691de2a08482de3d8ad0
|
|
| BLAKE2b-256 |
af81b9f39b121235b40d2ecc706a170f4631bcea6021b9290d70400350056172
|
File details
Details for the file enconvert-0.0.1-py3-none-any.whl.
File metadata
- Download URL: enconvert-0.0.1-py3-none-any.whl
- Upload date:
- Size: 29.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ad0a55ce87e3fab8fd22f7bd6f7310d7614519792e415f4059e775119452942c
|
|
| MD5 |
8de340df7cdeb82dca73dd28d33cd777
|
|
| BLAKE2b-256 |
97a47a376d7cf244ea4b69471c7de5bc59783beaaceeaa7b7c184d2da43531a8
|