API Documentation

Welcome to the MarkShot API documentation. Learn how to convert any webpage to clean, AI-friendly markdown with a single API call.

Introduction

MarkShot provides a simple REST API that converts webpages into clean, structured Markdown. Our service handles headless browser rendering, content extraction, and noise removal so you get pure, LLM-ready content.

Key features:

  • JavaScript rendering — Full Chromium-based rendering for dynamic content
  • Smart cleanup — Automatic removal of scripts, styles, SVGs, and boilerplate
  • Fast processing — Most pages processed in under 3 seconds
  • Simple pricing — Pay-as-you-go with no monthly fees

Registration

To use the MarkShot API, you'll need to create an account and generate an API key.

Create an account

Sign up at markshot.dev/accounts/signup/ with your email address. You'll receive {{ DEFAULT_CREDITS }} free credits to get started.

Verify your email

Check your inbox for a verification email and click the link to activate your account.

Generate an API key

Once verified, go to your API Keys dashboard and create a new key. Keep this key secure — it grants access to your account.

⚠️

Important: You cannot create API keys until your email is verified. Check your spam folder if you don't see the verification email.

Quickstart

Here's the fastest way to make your first API request:

bash
curl -X POST https://api.markshot.dev/v1/scrape \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

That's it! The API will return the page content as clean Markdown.

Authentication

All API requests require authentication using a Bearer token in the Authorization header:

http header
Authorization: Bearer YOUR_API_KEY

You can create and manage API keys from your dashboard. Each key has full access to your account, so keep them secure and rotate them if compromised.

💡

Tip: Store your API key in an environment variable rather than hardcoding it in your source code.

Scrape Endpoint

The scrape endpoint converts a webpage URL into Markdown.

POST https://api.markshot.dev/v1/scrape

Request Parameters

Send a JSON body with the following parameters:

Parameter Type Description
url required string The full URL of the webpage to scrape. Must include the protocol (http:// or https://).
timeout optional integer Maximum time in seconds to wait for the page to load. Default: 30. Range: 1-300.
retries optional integer Number of times to retry if the scrape fails. Default: 0. Range: 0-5.
retry_delay optional integer Seconds to wait between retries. Default: 10. Range: 5-30.

Response Format

Successful responses return JSON with the following structure:

json
{
  "success": true,
  "url": "https://example.com",
  "markdown": "# Example Domain\n\nThis domain is for use in illustrative examples...",
  "duration_seconds": 1.523
}

Response Fields

Field Type Description
success boolean Whether the scrape was successful.
url string The URL that was scraped (may differ from input if redirected).
markdown string The extracted content in Markdown format.
duration_seconds float Time taken to process the request in seconds.

Code Examples

Here are complete examples in popular languages:

# Basic request
curl -X POST https://api.markshot.dev/v1/scrape \
  -H "Authorization: Bearer $MARKSHOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "timeout": 60
  }'
import httpx
import os

API_KEY = os.environ.get("MARKSHOT_API_KEY")
API_URL = "https://api.markshot.dev/v1/scrape"

def scrape_to_markdown(url, timeout=30):
    response = httpx.post(
        API_URL,
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json"
        },
        json={
            "url": url,
            "timeout": timeout
        }
    )
    response.raise_for_status()
    return response.json()

# Example usage
result = scrape_to_markdown("https://example.com")
print(result["markdown"])
// Browser / Frontend JavaScript
const API_KEY = 'your_api_key'; // Don't expose in frontend!

async function scrapeToMarkdown(url) {
  const response = await fetch('https://api.markshot.dev/v1/scrape', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ url })
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return response.json();
}

// Example usage
const result = await scrapeToMarkdown('https://example.com');
console.log(result.markdown);
// Node.js with built-in fetch (Node 18+)
const API_KEY = process.env.MARKSHOT_API_KEY;

async function scrapeToMarkdown(url, options = {}) {
  const response = await fetch('https://api.markshot.dev/v1/scrape', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      url,
      ...options
    })
  });

  const data = await response.json();

  if (!response.ok) {
    throw new Error(data.error || 'Request failed');
  }

  return data;
}

// Example usage
const result = await scrapeToMarkdown('https://example.com', {
  timeout: 60,
  retries: 2
});
console.log(result.markdown);

Error Codes

The API uses standard HTTP status codes to indicate success or failure:

200

OK

Request successful. The response body contains the scraped Markdown content.

400

Bad Request

Invalid request parameters. Check that url is provided and properly formatted with a valid protocol (http:// or https://).

401

Unauthorized

Missing or invalid API key. Ensure you're including the Authorization: Bearer YOUR_API_KEY header.

402

Insufficient Credits

Your account has run out of credits. Purchase more credits to continue using the API.

429

Too Many Requests

You have too many concurrent scrape jobs in flight. Wait for some to complete before submitting new requests. The response includes a Retry-After header.

500

Internal Server Error

Something went wrong on our end. Try again later or contact support if the issue persists.

Error Response Format

Error responses include a JSON body with details:

json
{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_CREDITS",
    "message": "Your account has 0 credits remaining. Please purchase more credits to continue."
  }
}

Troubleshooting

Common Issues

🔍

Empty or incomplete content? Some pages load content dynamically with JavaScript. Try increasing the timeout parameter to give the page more time to fully render before scraping.

🔍

Getting 429 errors? You have too many concurrent requests. MarkShot processes requests asynchronously — wait for current jobs to complete before submitting more. Consider adding a small delay between requests.

🔍

Can't create API keys? Make sure you've verified your email address. Check your spam folder for the verification email, or request a new one from the dashboard.

🔍

Scrape taking too long? Complex pages with lots of JavaScript may take longer to process. If a request times out, try again — our workers will retry failed jobs automatically.

FAQ

How many credits does each scrape cost?

Each successful scrape costs 1 credit. Failed scrapes (due to invalid URLs, timeouts, etc.) do not consume credits.

Do credits expire?

No, credits never expire. Use them whenever you need.

What's the maximum page size you can scrape?

We can handle pages up to 10MB in size. For larger pages, we'll return the content we were able to extract before hitting the limit.

Can I scrape pages that require login?

Currently, we only support publicly accessible pages. Pages behind authentication or paywalls cannot be scraped.

How many concurrent requests can I make?

You can have up to 10 concurrent scrape jobs in flight at any time. If you need higher limits, contact us to discuss enterprise options.

Can I get a refund?

Yes! We offer full refunds on unused credits, no questions asked. Contact support to request a refund.

How is MarkShot different from just fetching a web page with curl?

Curl only fetches raw HTML, it can't execute JavaScript. Modern websites render content dynamically with React, Vue, Next.js, etc. You'll get an empty shell or loader placeholders. MarkShot uses headless Chromium to fully render pages, then strips scripts, styles, and boilerplate to give you clean Markdown ready for LLMs.

Why is MarkShot better than running Chrome in headless mode?

You could run headless Chrome yourself, but then you need to: set up and maintain Chromium, handle browser crashes and memory leaks, write HTML-to-Markdown conversion logic, implement retry handling, and scale your infrastructure. MarkShot abstracts all of that into a single API call. One POST request, clean Markdown back.

How are you different from Firecrawl, Apify, Tavily or other scraper APIs?

Simpler and more focused. MarkShot does one thing well: convert URLs to Markdown. No crawling engines, no data pipelines, no compute credits or monthly subscriptions. Pay-as-you-go credits that never expire, full refunds on unused credits, and a single /v1/scrape endpoint. If you need markdown for AI/RAG pipelines without the complexity, that's us.

Need Help?

Can't find what you're looking for? Our team is here to help.

Contact Support →