# Markovo Developer Guide

Markovo converts files and explicitly authorized public HTTPS pages into clean Markdown through one account-metered API. PDF is live; public URL import, DOCX, PPTX, XLSX, XLS, ODS, TXT, Markdown, JSON, XML, RTF, IPYNB, EML, MSG, HTML, CSV, PNG, JPEG, WebP, TIFF, BMP, EPUB, Notion Export ZIP, audio, and video audio tracks require a signed-in account. API, CLI, and MCP conversion requires authentication; supported Web inputs may use a bounded guest preview, with sign-in and account settlement required before download. Every active plan includes API, CLI, and MCP access within its limits; Free includes one active API key.

- Base URL: `https://markovo.net`
- Create or revoke keys: `https://markovo.net/app#developer`
- Capability discovery: `GET /v1/capabilities`
- Pricing catalog: `GET /v1/catalog`
- OpenAPI 3.1 schema: `https://markovo.net/openapi.json`
- API key prefix: `mk_live_`
- Required scope: `markovo:convert`

Never place an API key in browser code, public repositories, prompts, or analytics. Plaintext is shown once when the key is created.

## Environment

```bash
export MARKOVO_BASE_URL="https://markovo.net"
export MARKOVO_API_KEY="mk_live_..."
```

## API

The compatibility shortcut estimates, confirms the Credit ceiling, and queues one or more supported files. New clients should set integer `max_credit_units` (`1 Credit = 1,000 credit_units`) and send the matching `capability_id`. `max_credits` remains compatible with decimal values down to `0.001`.

For retry-safe automation, use `POST /v1/estimates` followed by `POST /v1/jobs`. The returned `upload_id` permanently identifies that confirmation: the first confirmation returns `201`, and an identical replay returns the existing job with `200` without creating a duplicate job or reserving additional Credits. A replay with a different ceiling returns the non-retryable `409 idempotency_conflict` error. The official CLI and MCP client use this two-step flow and only replay the same confirmation after an ambiguous network failure. Do not automatically retry the `/v1/convert` compatibility shortcut after an unknown response.

```bash
curl -X POST "${MARKOVO_BASE_URL}/v1/convert" \
  -H "Authorization: Bearer ${MARKOVO_API_KEY}" \
  -F "file=@paper.pdf" \
  -F "capability_id=pdf-to-markdown" \
  -F "mode=fast" \
  -F "max_credit_units=30000"
```

Signed-in conversion example:

```bash
curl -X POST "${MARKOVO_BASE_URL}/v1/convert" \
  -H "Authorization: Bearer ${MARKOVO_API_KEY}" \
  -F "file=@notes.md" \
  -F "capability_id=text-to-markdown" \
  -F "mode=fast" \
  -F "max_credit_units=1000"
```

Formula-dense PDFs run through the standard conversion pipeline, which routes scanned and complex
pages to the Markovo OCR engine that renders equations as reviewable LaTeX. The legacy
`layout_fidelity=formula` option is still accepted for API compatibility and is handled as standard
conversion at the normal page rate — no separate formula charge applies. The result must be reviewed
against the original source.

```bash
curl -X POST "${MARKOVO_BASE_URL}/v1/convert" \
  -H "Authorization: Bearer ${MARKOVO_API_KEY}" \
  -F "file=@formula.pdf" \
  -F "capability_id=pdf-to-markdown" \
  -F "max_credit_units=5000"
```

URL to Markdown uses a JSON estimate endpoint. Supported sources include public HTML/text, public Google Docs, Notion pages and bounded databases, GitHub text resources and discussions, Hacker News threads, and downloadable YouTube videos. Every entry point authorizes a specific public source before fetching it; the sandbox sends no browser cookies or customer credentials and follows bounded public redirects and content rules. Private or login-only sources, Tencent Docs account connections, browser-only pages, generic binary downloads, and remote document images are not supported. API examples use ordinary HTTP clients, not a separate Markovo SDK:

```bash
curl -X POST "${MARKOVO_BASE_URL}/v1/url-estimates" \
  -H "Authorization: Bearer ${MARKOVO_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/public-report","accept_remote_fetch":true}'

markovo url-convert https://example.com/public-report \
  --out runs/public-report --max-credits 1 --accept-remote-fetch
```

Read the estimate, then replace `upl_RETURNED_UPLOAD_ID` below with its returned `upload_id`. Confirm only when `estimated_credit_units` fits your chosen ceiling (15,000 units = 15 Credits):

```bash
curl -X POST "${MARKOVO_BASE_URL}/v1/jobs" \
  -H "Authorization: Bearer ${MARKOVO_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"upload_id":"upl_RETURNED_UPLOAD_ID","max_credit_units":15000}'
```

Ordinary public documents retain the URL fetch-time and word-count rate. YouTube uses `audio-to-markdown` billing at 0.5 Credits per decoded minute, minimum 0.3 Credit, with limits of one hour and 32 MB plus the account upload limit. Captions are not required; video frames are not analyzed. Do not put private, signed, credential-bearing, or access-controlled URLs into this route.

Web guests receive `job_token` with an anonymous URL estimate. The Web flow submits `{"estimates":[{"upload_id":"...","job_token":"..."}]}` to `POST /v1/guest-preview-sessions`, keeps the returned `session_token` for claim after sign-in, and uses `x-markovo-job-token` to poll jobs and view previews. The preview queue has a 5-Credit estimated ceiling and daily limits; download requires sign-in and settlement from account Credits. API-key examples above use authenticated direct confirmation.

CSV uses the same flow. Active Credit v2 billing has a 0.07 Credit minimum and then follows measured non-empty cells at 0.05 Credit per 2,000 cells with unit-level rounding:

```bash
curl -X POST "${MARKOVO_BASE_URL}/v1/convert" \
  -H "Authorization: Bearer ${MARKOVO_API_KEY}" \
  -F "file=@people.csv" \
  -F "capability_id=csv-to-markdown" \
  -F "mode=fast" \
  -F "max_credit_units=1000"
```

Image OCR uses the same account and History, preserves the source image in the bundle, and bills 0.5 Credit per actual OCR page. The server may choose the best conversion method without changing the confirmed price:

```bash
curl -X POST "${MARKOVO_BASE_URL}/v1/convert" \
  -H "Authorization: Bearer ${MARKOVO_API_KEY}" \
  -F "file=@scan.png" \
  -F "capability_id=image-to-markdown" \
  -F "mode=fast" \
  -F "max_credit_units=3000"
```

Audio accepts MP3, WAV, M4A, AAC, FLAC, OGG, OPUS, and WMA. Video accepts MP4, MOV, M4V, WebM, MKV, AVI, and WMV and transcribes only its audio track. Active Credit v2 billing follows actual decoded milliseconds: Audio and Video both use 0.5 Credits per minute, with a 0.3 Credit minimum, a 50 MiB limit, and a 60-minute limit. The server decodes duration before confirmation, reserves the exact estimate, then settles verified duration without exceeding the confirmed ceiling. Failed jobs spend nothing.

```bash
curl -X POST "${MARKOVO_BASE_URL}/v1/convert" \
  -H "Authorization: Bearer ${MARKOVO_API_KEY}" \
  -F "file=@meeting.mp3" \
  -F "capability_id=audio-to-markdown" \
  -F "mode=fast" \
  -F "max_credit_units=60000"

curl -X POST "${MARKOVO_BASE_URL}/v1/convert" \
  -H "Authorization: Bearer ${MARKOVO_API_KEY}" \
  -F "file=@recording.mp4" \
  -F "capability_id=video-to-markdown" \
  -F "mode=fast" \
  -F "max_credit_units=60000"
```

The transcript includes timestamps, detected language, decoded duration, and actual Credits. This conversion does not analyze video frames, identify speakers, or guarantee a verbatim transcript.

Office files use the same bounded flow. Active Credit v2 billing is 0.1 Credit per measured DOCX page or detected PPTX slide:

```bash
markovo convert report.docx --out runs/report --max-credits 10
markovo convert deck.pptx --out runs/deck --max-credits 3
```

Modern XLSX workbooks have a 0.11 Credit minimum, then use 0.05 Credit per 2,000 measured non-empty cells with unit-level rounding. Formulas remain text; Markovo does not calculate them or follow external links:

```bash
markovo convert workbook.xlsx --out runs/workbook --max-credits 5
```

Poll the returned `job_id`, then download Markdown:

```bash
curl "${MARKOVO_BASE_URL}/v1/jobs/{job_id}" \
  -H "Authorization: Bearer ${MARKOVO_API_KEY}"

curl -L "${MARKOVO_BASE_URL}/v1/jobs/{job_id}/download?format=md" \
  -H "Authorization: Bearer ${MARKOVO_API_KEY}" \
  -o output.md
```

For explicit cost confirmation, use `POST /v1/estimates` followed by `POST /v1/jobs`. `GET /v1/jobs` lists only the current account's jobs. Job lookup, downloads, quality reports, and deletion enforce account ownership.

To give an AI client temporary online access to one extracted image, first list
the manifest-verified assets, then create a 60–600 second grant. The URL is a
bearer capability: do not log, forward, or persist it. It can be revoked early;
the underlying object storage is never exposed. An expired or revoked grant URL returns not found;
request a new grant only while the owned job and asset still exist.

```bash
curl "${MARKOVO_BASE_URL}/v1/jobs/{job_id}/assets" \
  -H "Authorization: Bearer ${MARKOVO_API_KEY}"

curl -X POST "${MARKOVO_BASE_URL}/v1/jobs/{job_id}/asset-grants" \
  -H "Authorization: Bearer ${MARKOVO_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"asset_path":"assets/chart.png","expires_in_seconds":300}'
```

## CLI

Install the pinned client and use the same API key and Credit balance:

```bash
python -m pip install --force-reinstall "https://markovo.net/downloads/markovo-0.1.1-py3-none-any.whl#sha256=aae71e1fff133fca3a9e6c17a1fd3b1080a0bd5a05ea075eef7267491bea079d"
markovo doctor --json
markovo convert paper.pdf --out runs/paper --mode fast --max-credits 30
markovo convert notes.md --out runs/notes --mode fast --max-credits 5
markovo convert people.csv --out runs/people --mode fast --max-credits 5
markovo convert scan.png --out runs/scan --mode fast --max-credits 3
markovo convert report.docx --out runs/report --mode fast --max-credits 10
markovo convert deck.pptx --out runs/deck --mode fast --max-credits 3
markovo convert workbook.xlsx --out runs/workbook --mode fast --max-credits 5
markovo convert meeting.mp3 --out runs/meeting --mode fast --max-credits 60
markovo convert recording.mp4 --out runs/recording --mode fast --max-credits 60
markovo convert formula.pdf --out runs/formula --max-credits 5
markovo assets {job_id}
markovo asset-url {job_id} assets/chart.png --expires-in-seconds 300
markovo asset-revoke {job_id} {grant_id}
markovo usage
markovo billing
```

`markovo billing` returns a secure browser URL. Customer conversion uses the remote product API; local development tools require an explicit development flag.

## MCP

For a hosted client, connect `https://markovo.net/mcp` as a Streamable HTTP
server. The client uses OAuth 2.1 Authorization Code with PKCE, opens Markovo's
sign-in and consent screens, and receives only approved account scopes. Do not
create or paste an API key for the remote connection.

Remote MCP exposes nine tools for capabilities, Credit usage, owned jobs,
public-HTTPS URL conversion, verified result images, short-lived asset links,
and billing help. It cannot read a local file and exposes no shell, credential,
payment, or administrator tool. `markovo_convert_url` requires a positive
`max_credit_units` cap. Markovo never tops up Credits or changes a plan
automatically; a low-balance result points the account owner to
`https://markovo.net/app#billing`. See `https://markovo.net/docs/mcp`.

### Local stdio MCP

Local stdio MCP uses `MARKOVO_API_KEY`. Its `markovo_convert_url` tool takes `url`, `out_dir` within `MARKOVO_MCP_ROOT`, `accept_remote_fetch: true`, and `max_credits` in Credits. Remote OAuth MCP instead uses the required positive integer `max_credit_units` and cannot read local files.

The customer MCP server exposes these exact 11 `tools/list` names:

- `markovo_convert`
- `markovo_convert_url`
- `markovo_job_status`
- `markovo_job_assets`
- `markovo_asset_url`
- `markovo_asset_revoke`
- `markovo_usage`
- `markovo_capabilities`
- `markovo_billing`
- `markovo_bundle_verify`
- `markovo_doctor`

It provides remote conversion, job status, temporary Bundle image access,
usage, billing, and diagnostics over stdio. Use
`markovo_job_assets` → `markovo_asset_url`; revoke early with
`markovo_asset_revoke`.

```json
{
  "mcpServers": {
    "markovo": {
      "command": "markovo-mcp",
      "env": {
        "MARKOVO_API_KEY": "${MARKOVO_API_KEY}",
        "MARKOVO_MCP_ROOT": "/path/to/dedicated/project"
      }
    }
  }
}
```

The human CLI and local stdio MCP use a **15-Credit convenience safety ceiling** when the caller omits the maximum. Markovo obtains an estimate internally before job creation and rejects work estimated above that ceiling; the client does not pause for user confirmation. Set an **explicit bound for deliberate automation**. REST remains explicit, as do direct programmatic client calls. MCP, CLI, and HTTP API all settle against the same `conversion.credits` ledger.

`markovo_convert` requires local filesystem paths (`input_path` and `out_dir`) inside the explicitly configured `MARKOVO_MCP_ROOT`. File tools fail closed when the root is missing and reject parent-directory, absolute-path, and symlink escapes. API keys and the service origin are never MCP tool arguments. Agents without a mounted disk or without access to the source file inside that dedicated root must use REST multipart upload instead. A Word conversion uses the same customer capability contract:

```json
{
  "input_path": "/absolute/path/report.docx",
  "out_dir": "/absolute/path/runs/report",
  "capability_id": "docx-to-markdown",
  "max_credits": 10
}
```

## Output contract

A completed conversion can produce:

- `output.md`
- `assets/`
- `metadata.json`
- `source_map.json`
- `quality_report.json`
- `bundle.zip`

For a completed Job, `GET /v1/jobs/{job_id}/source-map` returns the
customer-safe page and block provenance used by the browser review workbench.
It uses the same account API key or anonymous `x-markovo-job-token` ownership
check as the result downloads and omits internal providers, routes, paths,
hashes, statistics, and arbitrary metadata. The original source file is not
retained by this endpoint.

## Errors

Public errors contain `code`, `message`, `request_id`, `retryable`, and `docs_url`. Retry only when `retryable` is true. Do not retry quota, ownership, validation, or Credit-ceiling errors without changing the request.

## AI-readable references

- Full public docs: `https://markovo.net/docs`
- Capability status and roadmap: `https://markovo.net/capabilities.md`
- AI integration contract: `https://markovo.net/ai-native.md`
- Site index for language models: `https://markovo.net/llms.txt`
- Machine-readable HTTP contract: `https://markovo.net/openapi.json`


# Connect Markovo — Agent Playbook

You are setting up Markovo for a user. Markovo converts files (PDF, DOCX, PPTX, XLSX, images, audio, video, EPUB, CSV, text) and explicitly authorized public HTTPS pages into clean Markdown bundles. Follow these steps in order and keep the user informed briefly at each step.

> This file is the quick playbook for agents. The full interactive guide — with per-method walkthroughs — lives at `https://markovo.net/docs` (the Connect page). Fetch it if this file does not cover the user's situation.

## Step 1 — Choose the connection

Pick the first method the user's client supports, and tell the user why you chose it. When in doubt: **remote MCP for AI assistants, REST API for software, CLI for humans in a terminal.**

| # | Method | Best for | Needs API key |
|---|--------|----------|---------------|
| 1 | Remote MCP | AI assistants (Claude, ChatGPT, Cursor…) | No — OAuth sign-in |
| 2 | Local stdio MCP | Agents that must upload local files | Yes |
| 3 | CLI | Terminals, scripts, CI | Yes |
| 4 | REST API | Products and backends | Yes |

1. **Remote MCP (recommended for AI assistants)** — URL `https://markovo.net/mcp`, transport Streamable HTTP, auth OAuth 2.1 Authorization Code + PKCE. If the user's MCP client supports remote servers with OAuth, register this URL. The client opens a normal sign-in plus a consent screen; no API key is created or pasted. Remote MCP can convert public URLs and inspect owned jobs, usage, and billing guidance; it cannot upload local files.
2. **Local stdio MCP (local files for agents)** — install the client package, then configure an MCP server entry:
   ```json
   {
     "mcpServers": {
       "markovo": {
         "command": "markovo-mcp",
         "env": {
           "MARKOVO_API_KEY": "<api key>",
           "MARKOVO_MCP_ROOT": "/path/to/dedicated/project"
         }
       }
     }
   }
   ```
3. **CLI (terminal / scripts)** — `pip install "https://markovo.net/downloads/markovo-0.1.1-py3-none-any.whl#sha256=aae71e1fff133fca3a9e6c17a1fd3b1080a0bd5a05ea075eef7267491bea079d"`, then `export MARKOVO_API_KEY="mk_live_..."` and run `markovo convert file.pdf --out runs/out --max-credits 30`.
4. **REST API (products and backends)** — `POST https://markovo.net/v1/convert` with `Authorization: Bearer mk_live_...`, multipart `file` fields and a mandatory `max_credits` ceiling. Poll `GET /v1/jobs/{id}`, download via `GET /v1/jobs/{id}/download?format=md|zip`.

## Step 2 — Account and API key (skip for remote MCP OAuth)

1. Ask the user to open `https://markovo.net/app`, sign in (Google, GitHub, or email), and create an API key under **API keys** (`/app#developer`). The key is shown once, starts with `mk_live_`, and carries the `markovo:convert` scope.
2. Have the user paste the key where you tell them — an env var (`MARKOVO_API_KEY`), the MCP `env` block, or a server secret. Never ask them to put it in browser code or commit it.
3. Free accounts include 25 monthly Credits and one active API key; paid plans add capacity and retention.

## Step 3 — Verify

- Remote MCP: confirm the OAuth flow completed and list the exposed tools.
- API key: `curl -H "Authorization: Bearer $MARKOVO_API_KEY" https://markovo.net/v1/capabilities` must return 200.
- CLI: `markovo doctor --json` must report ok.

Report success with one line: method used, what the user can now ask you to convert, and where results land.

## Reference (fetch when needed)

- Full connection guide (Connect page): `https://markovo.net/docs`
- Capability status: `https://markovo.net/capabilities.md`
- Full API contract: `https://markovo.net/openapi.json`
- Copy-ready developer guide: `https://markovo.net/developer.md`
- Machine-readable site index: `https://markovo.net/llms.txt`
- Remote MCP guide: `https://markovo.net/docs/mcp`

Every conversion needs an explicit Credit ceiling (`max_credits` / `max_credit_units`); failed or cancelled jobs charge zero. Always obtain a user-approved maximum before submitting work.
