V1 and V2: Convert Files or Read the Web#

The EnConvert API has two halves. V1 (/v1/convert/...) turns a file or a URL into a format you name; V2 (/v2/...) reads a live web page and hands back data an agent can use. One key covers both halves at one base URL, and both bill the same meter.

Live today: all of V1, plus all six V2 endpoints. Perceive and Ingest are generally available. Distill, Lookup, Watch and Discover are callable but in private beta, documented under Coming Soon, and their shapes can change without notice.

The decision rule#

If you already know the output format you want, that is V1. If you want to know what is on a page, that is V2.

What you are doing Half Start here
Turn this URL into a PDF V1 url-to-pdf
Turn this DOCX into a PDF V1 Documents
Turn this JSON into YAML V1 Data formats
Turn this HEIC into a WebP V1 Images
Read this page as Markdown for an LLM V2 Perceive
Get Markdown, a screenshot, links and metadata from one render V2 Perceive
Turn a whole site into RAG chunks V2 Ingest

The awkward edge: url-to-markdown (V1) and perceive (V2) overlap. Use V1 when you want one Markdown file and nothing else. Use V2 when you also want the screenshot, the links, the page metadata, or the option to stream the bytes back inline.


V1: deterministic conversion#

You send bytes or a URL, and the endpoint you call is the target format. POST /v1/convert/png-to-webp returns WebP. Nothing decides anything for you.

There are 49 single-target conversion endpoints across four families, plus two website crawlers that walk a whole site and return a ZIP, so 51 routes in all.

Family Endpoints Input
Web pages 5 A URL (or a list of URLs) in a JSON body
Documents 13 A file upload (multipart/form-data)
Data formats 11 A file upload (multipart/form-data)
Images 22 A file upload (multipart/form-data)

Of those, website-to-pdf and website-to-screenshot are the two crawlers: they discover pages under a domain and always answer asynchronously with 202 and a ZIP. Every other endpoint converts one input into one output. The full input-to-output map is on the conversion matrix.

A V1 call looks like this:

curl -X POST https://api.enconvert.com/v1/convert/url-to-pdf \
  -H "X-API-Key: sk_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/pricing"}'
{
    "presigned_url": "https://spaces.example.com/...signed...",
    "object_key": "env/files/{project_id}/url-to-pdf/example_20260404_123456789.pdf",
    "filename": "example_20260404_123456789.pdf",
    "file_size": 123456,
    "conversion_time_seconds": 12.5
}

Set direct_download=true on a single-URL sync request and the response body is the PDF itself instead of that JSON.


V2: reading the live web#

V2 renders a page in real headless Chrome (JavaScript executed, lazy content loaded) and returns what is on it: Markdown, cleaned or raw HTML, a screenshot, a PDF, the link and image inventory, structured page data, or RAG-ready chunks. You do not name an output format so much as name the outputs you want from one render.

Here is the smallest useful call. Send a URL to /v2/perceive, get clean Markdown and the page's structured metadata back:

curl -X POST https://api.enconvert.com/v2/perceive \
  -H "X-API-Key: sk_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/pricing",
    "outputs": ["markdown", "structured"]
  }'

The response carries a pre-signed download URL for the Markdown and the structured block inline:

{
    "operation_id": "per_3f9a2c1b8e7d4a6f90b1c2d3e4f5a6b7",
    "status": "completed",
    "url_final": "https://example.com/pricing",
    "render_quality": 0.93,
    "outputs": {
        "markdown": {
            "url": "https://spaces.example.com/...signed...",
            "size_bytes": 8421,
            "expires_in": 900
        }
    },
    "structured": {
        "metadata": {"title": "Pricing"}
    }
}

Send JSON, get a result inline or a short-lived signed URL to an artifact. That is the shape of every V2 endpoint.


What is live today#

All six V2 endpoints are callable. Two of them are generally available: Perceive and Ingest.

Endpoint Status What it does
POST /v2/perceive Live Render one URL once and return every output you asked for: Markdown, cleaned or raw HTML, screenshot, PDF, links, images, structured data.
POST /v2/ingest Live Crawl a site (or accept uploaded files) and emit one JSONL file of RAG-ready chunks, asynchronously behind a job_id.
Distill Private beta Reference
Lookup Private beta Reference
Watch Private beta Reference
Discover Private beta Reference
The bottom four rows are private beta. Distill, Lookup, Watch and Discover answer real requests today, but they are not announced, not generally available, and their request and response shapes can change without notice, so keep them out of anything load-bearing. Watch needs a paid plan; the other three run on every plan, Founding included. Details are under Coming Soon.

What the two halves share#

V2 is additive. The V1 endpoints are unchanged and unaffected by any of it. There is no migration: you add V2 next to V1 when you need it.

One key. A sk_ private key in the X-API-Key header, or a pk_ public key exchanged for a JWT bearer token, works across V1 and V2 identically. See authentication for the full flow, including domain locking and token refresh.

One allowlist. Each API key carries an allowed-endpoints list. A V2 path that is not on the key's list is rejected with 403, exactly as a V1 path would be.

One meter. V1 conversions and V2 operations bill the same monthly ops counter. One op is one unit of work: one conversion, one URL perceived, one page ingested. There are no per-endpoint multipliers, so an expensive render costs the same op as a JSON-to-YAML conversion. Plan allowances are on rate limits and quotas.

One delivery mechanism. File output from either half is uploaded to storage and returned as a pre-signed URL that expires after 15 minutes (expires_in: 900). Re-fetch the operation, job, or batch to mint a fresh set; re-signing re-renders nothing and costs no ops. Details on signed URLs.


Design choices that hold across V2#

Learn these once and they apply across V2.

One render through a shared browser. Perceive and Ingest render through the same headless Chrome singleton and the same capture pipeline that backs the V1 url-to-pdf endpoint. Cookie banners are dismissed, the page is scrolled to trigger lazy content, and images are given time to load.

SSRF protection on every URL. Before any fetch or render, each URL is screened for scheme, embedded credentials, blocked hostnames, and the resolved IP. A URL that resolves to a private, loopback, link-local, or cloud-metadata address is rejected with 400. That applies to seeds and to crawled links alike.

Render-quality scoring. Every render carries a render_quality score from 0.0 to 1.0. A low score flags a page that looks blocked by anti-bot protection or hidden behind a login wall, so you can tell a real capture from a challenge page.

Credentials only where they are safe. Perceive accepts auth, cookies, and custom headers for pages behind a login. Ingest deliberately does not, because its jobs are durable and resumable and nothing secret should be persisted for a resume. Need credentials for one page in an ingest set? Render it through perceive instead.

Reserved parameters say so. Where a parameter is accepted by the schema but not yet wired up, V2 tells you rather than silently ignoring it. Perceive's proxy_url, geolocation, and action_chain return 422 today; its prices, contacts, and technologies extract names land in warnings and are dropped.

V2 is in beta. Pin your integration to the documented field names and status codes, read warnings on every response, and expect response bodies to gain fields before V2 leaves beta. New fields may appear; documented ones will not silently change meaning.

Where to start#

If you have not made a first call yet, the quickstart walks through getting a key and running one request end to end.


Frequently asked questions#

Do I need a separate API key for V2?#

No. One key covers both halves. A sk_ private key in the X-API-Key header, or a JWT minted from a pk_ public key, authenticates V1 and V2 identically, subject to the key's allowed-endpoints list.

Does V2 replace V1?#

No. V2 is additive and V1 is unchanged. If you want a named output format from a file or a URL, V1 is still the right call, and it stays that way.

How is usage counted across V1 and V2?#

Both halves bill one monthly ops counter, and one op is one unit of work: one V1 conversion, one URL perceived, one page ingested. There is no per-endpoint weighting. See rate limits and quotas.

Which V2 endpoints can I call today?#

All six. Perceive and Ingest are generally available. Distill, Lookup, Watch and Discover are in private beta: callable with your normal key, documented under Coming Soon, free to change shape without notice, and Watch additionally needs a paid plan.