# Deepread Api

> Full DeepRead API reference. All endpoints, auth, request/response formats, blueprints, webhooks, error handling, and code examples for OCR, structured extraction, form filling, and PII redaction.

- **Type:** Skill
- **Install:** `agentstack add skill-deepread-tech-skills-api`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [deepread-tech](https://agentstack.voostack.com/s/deepread-tech)
- **Installs:** 0
- **Category:** [Content & Media](https://agentstack.voostack.com/c/content-and-media)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [deepread-tech](https://github.com/deepread-tech)
- **Source:** https://github.com/deepread-tech/skills/tree/main/skills/api

## Install

```sh
agentstack add skill-deepread-tech-skills-api
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# DeepRead API Reference

You are helping a developer integrate DeepRead into their application. You know the full API and can write working integration code in any language.

**Base URL:** `https://api.deepread.tech`
**Auth:** `X-API-Key` header with key from `https://www.deepread.tech/dashboard` or via the device authorization flow (see Agent Authentication below)

---

## Agent Authentication (Device Authorization Flow)

These endpoints let an AI agent obtain an API key without the user ever copy/pasting secrets. Based on OAuth 2.0 Device Authorization Grant (RFC 8628).

### POST /v1/agent/device/code — Request a Device Code

**Auth:** None (public endpoint)
**Content-Type:** `application/json`

```json
{"agent_name": "my-agent"}
```

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `agent_name` | string | No | Display name shown to the user during approval (e.g. "Claude Code", "My CI Bot"). Optional but strongly recommended — without it, the user sees "Unknown Agent". |

**Response (200 OK):**
```json
{
  "device_code": "a7f3c9d2e1b8...",
  "user_code": "HXKP-3MNV",
  "verification_uri": "https://www.deepread.tech/activate",
  "verification_uri_complete": "https://www.deepread.tech/activate?code=HXKP-3MNV",
  "expires_in": 900,
  "interval": 5
}
```

| Field | Description |
|-------|-------------|
| `device_code` | Secret code for polling — never show this to the user |
| `user_code` | Short code the user enters in their browser (format: `XXXX-XXXX`) |
| `verification_uri` | Base URL for manual code entry |
| `verification_uri_complete` | URL with code pre-filled — open this to skip manual entry (preferred) |
| `expires_in` | Seconds until the code expires (default: 900 = 15 minutes) |
| `interval` | Minimum seconds between poll requests |

---

### POST /v1/agent/device/token — Poll for API Key

**Auth:** None (public endpoint)
**Content-Type:** `application/json`

```json
{"device_code": "a7f3c9d2e1b8..."}
```

Poll this endpoint every `interval` seconds after the user has been shown the code.

**Responses:**

| Scenario | `error` field | `api_key` field | Action |
|----------|---------------|-----------------|--------|
| User hasn't acted yet | `"authorization_pending"` | `null` | Wait `interval` seconds, poll again |
| User approved | `null` | `"sk_live_..."` | Save the key, stop polling |
| User denied | `"access_denied"` | `null` | Stop polling, inform user |
| Code expired | `"expired_token"` | `null` | Start over with a new device code |

The response always includes all three fields (`error`, `api_key`, `key_prefix`). Check `api_key != null` to detect success — don't rely on key presence alone.

**Important:**
- The `api_key` is returned **exactly once**. After you retrieve it, the server clears it. Store it immediately.
- The `key_prefix` is a non-secret identifier for the key (useful for display/logging).
- Never show `device_code` or `api_key` to the user.

---

**What happens on the user's side (you don't need to call these):**
- User opens `verification_uri_complete` — the code is pre-filled, no typing needed
- User logs in (or signs up + confirms email for new users)
- User sees your agent name and clicks Approve → redirected to dashboard
- Once approved, the next poll to `/v1/agent/device/token` returns the `api_key`

---

## Processing

### POST /v1/process — Submit a Document

Uploads a document for async processing. Returns immediately with a job ID.

**Auth:** `X-API-Key: YOUR_KEY`
**Content-Type:** `multipart/form-data`

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `file` | File | Yes | — | PDF, PNG, JPG, or JPEG |
| `pipeline` | string | No | `"standard"` | Accuracy tier: `"standard"` (multi-model consensus) or `"fast"` (single-pass OCR) |
| `searchable_pdf` | string | No | `"false"` | Set `"true"` to also produce a searchable PDF. **Standard tier only.** |
| `schema` | string | No | — | JSON Schema for structured extraction |
| `blueprint_id` | string | No | — | Blueprint UUID (mutually exclusive with schema) |
| `include_images` | string | No | `"true"` | Generate preview images and page data |
| `include_pages` | string | No | `"false"` | Per-page breakdown (auto-enabled when include_images=true) |
| `webhook_url` | string | No | — | HTTPS URL to notify on completion |
| `version` | string | No | — | Pipeline version for reproducibility |

**Note:** Provide `schema` OR `blueprint_id`, not both. Without either, only OCR text is returned.

**Response (200 OK):**
```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "queued"
}
```

**Errors:**
| Status | Meaning |
|--------|---------|
| 400 | Invalid schema, unsupported file type, both schema and blueprint_id provided |
| 401 | Invalid or missing API key |
| 413 | File exceeds plan limit (15MB free, 50MB paid) |
| 429 | Monthly page quota exceeded or rate limit hit |

---

### GET /v1/jobs/{job_id} — Get Results

Poll until `status` is `completed` or `failed`. Recommended: wait 5s, then poll every 5-10s with exponential backoff, max 5 minutes.

**Auth:** `X-API-Key: YOUR_KEY`

**Response (completed):**

Every response carries `"schema_version": "dp02"`.

```json
{
  "id": "550e8400-...",
  "status": "completed",
  "schema_version": "dp02",
  "pipeline": "standard",
  "created_at": "2025-01-18T10:30:00Z",
  "completed_at": "2025-01-18T10:32:15Z",
  "document": {
    "page_count": 3,
    "content": {
      "format": "markdown",
      "text": "Full extracted text in markdown",
      "text_preview": "First 500 characters...",
      "text_url": "https://..."
    },
    "layout": {
      "version": "dp.lite.v1",
      "page": {"index": 1},
      "layout": {"blocks": [{"id": "b1", "type": "heading", "content": "INVOICE"}]}
    }
  },
  "extraction": {
    "fields": [
      {"key": "vendor", "value": "Acme Inc", "needs_review": false, "location": {"page": 1}},
      {"key": "total", "value": 1250.00, "needs_review": true, "review_reason": "Outside typical range", "location": {"page": 1}}
    ]
  },
  "pages": [
    {
      "page_number": 1,
      "content": {"format": "markdown", "text": "Page 1 text..."},
      "fields": [],
      "needs_review": false
    }
  ],
  "review": {
    "needs_review": true,
    "quality_score": 0.96,
    "fields_total": 20,
    "fields_needing_review": 1,
    "review_rate": 0.05,
    "flags": [
      {"scope": "document", "severity": "high", "reason": "total outside typical range"}
    ]
  },
  "artifacts": {
    "preview_url": "https://preview.deepread.tech/token123..."
  },
  "webhook": {
    "url": "https://yourapp.com/webhook",
    "delivered": true
  },
  "meta": {
    "engine_version": "1.1.0",
    "cost_breakdown": {}
  }
}
```

**Notes:**
- `document.content.text_url` is provided when full text exceeds 1MB — fetch from this URL instead
- `document.content.text_preview` is always the first 500 characters
- `extraction.fields` is only present if `schema` or `blueprint_id` was provided — a **list** of `{key, value, needs_review, review_reason?, location.page}`
- `pages` is present when `include_pages=true` or `include_images=true`; per-page auto-detected fields are in `pages[].fields[]`
- `document.layout` is a typed object (was the old `result.json_string` blob)
- `artifacts.preview_url` is a shareable link (no auth needed) to the HIL review interface
- Bounding boxes (with `include_markers=true`) are returned under top-level `grounding[]`

**Response (failed):**
```json
{
  "id": "550e8400-...",
  "status": "failed",
  "error": "PDF parsing failed: file may be corrupted"
}
```

**Statuses:** `queued` → `processing` → `completed` or `failed`

---

### GET /v1/preview/{token} — Public Preview (No Auth)

Returns document preview data. Anyone with the token can view — no API key needed. Use for sharing results with stakeholders.

```json
{
  "file_name": "invoice.pdf",
  "status": "completed",
  "created_at": "2025-01-18T10:30:00Z",
  "pages": [
    {
      "page_number": 1,
      "image_url": "https://...",
      "text": "Page text...",
      "hil_flag": false,
      "data": {}
    }
  ],
  "data": {},
  "metadata": {"page_count": 1, "pipeline": "standard", "review_percentage": 0}
}
```

---

### GET /v1/pipelines — List Pipelines (No Auth)

- **standard** — Multi-model consensus (GPT-5 Mini + Gemini 2.5 Flash), dual OCR with LLM judge, ~45-60s
- **fast** — Single-pass OCR for speed and lower cost

Searchable PDF is an **add-on, not a tier**: send `pipeline=standard` + `searchable_pdf=true` to also get a searchable PDF (`artifacts.searchable_pdf_url`). Legacy `pipeline=searchable` still works as an alias for that combination.

---

### Schema: Arrays of Objects

Array-valued fields (`"type": "array"`) can carry any `items.properties` you define — not just `{description, amount}`. Each property in `items.properties` is extracted as its own typed field per row, with your `datapoint_prompt` / `description` passed to the model.

```json
{
  "type": "object",
  "properties": {
    "documents": {
      "type": "array",
      "description": "Every invoice entry on the summary bill.",
      "items": {
        "type": "object",
        "properties": {
          "vendor_name":     {"type": "string"},
          "account_number":  {"type": ["string", "null"]},
          "invoice_date":    {"type": "string", "format": "date"},
          "invoice_total":   {"type": "number"},
          "line_items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "description": {"type": "string"},
                "amount":      {"type": "number"}
              }
            }
          }
        },
        "required": ["vendor_name", "invoice_total"]
      }
    }
  }
}
```

Notes:

- Nullable types use `"type": ["string", "null"]` (standard JSON Schema).
- Required properties inside `items` are enforced; optional ones default to `null`.
- Deep nesting (array → object → array → object) is supported up to 6 levels.
- The legacy two-field `{description, amount}` shape still works unchanged — existing integrations are unaffected.

---

## Blueprints & Optimizer

Blueprints are optimized, versioned schemas. The optimizer takes your sample documents + expected values and enhances field descriptions for 20-30% accuracy improvement.

### GET /v1/blueprints/ — List Blueprints

**Auth:** `X-API-Key: YOUR_KEY`

Returns all blueprints with active version and accuracy metrics.

### GET /v1/blueprints/{blueprint_id} — Get Blueprint Details

**Auth:** `X-API-Key: YOUR_KEY`

Returns blueprint with all versions, active version schema, and accuracy metrics.

### POST /v1/optimize — Start Optimization

**Auth:** `X-API-Key: YOUR_KEY`

```json
{
  "name": "utility_invoice",
  "description": "Utility bill extraction",
  "document_type": "invoice",
  "initial_schema": {"type": "object", "properties": {...}},
  "training_documents": ["path1.pdf", "path2.pdf"],
  "ground_truth_data": [{"vendor": "Electric Co", "total": 150.00}, ...],
  "target_accuracy": 95.0,
  "max_iterations": 5,
  "max_cost_usd": 10.0
}
```

- `initial_schema` is optional — auto-generated from ground truth if omitted
- Minimum 2 training documents
- `validation_split` (default 0.3) — fraction held out for validation

**Response:**
```json
{
  "job_id": "...",
  "blueprint_id": "...",
  "status": "pending"
}
```

### POST /v1/optimize/resume — Resume Optimization

Resume a failed job or start a new optimization run for an existing blueprint.

### GET /v1/blueprints/jobs/{job_id} — Optimization Job Status

**Auth:** `X-API-Key: YOUR_KEY`

```json
{
  "status": "running",
  "iteration": 2,
  "baseline_accuracy": 68.0,
  "current_accuracy": 88.0,
  "target_accuracy": 95.0,
  "total_cost": 1.82,
  "max_cost_usd": 10.0
}
```

**Statuses:** `pending` → `initializing` → `running` → `completed`, `failed`, or `cancelled`

### GET /v1/blueprints/jobs/{job_id}/schema — Get Optimized Schema

Returns the optimized JSON schema after optimization completes.

### Using a Blueprint

```bash
curl -X POST https://api.deepread.tech/v1/process \
  -H "X-API-Key: YOUR_KEY" \
  -F "file=@invoice.pdf" \
  -F "blueprint_id=660e8400-..."
```

---

## Webhooks

Pass `webhook_url` when submitting a document to get notified on completion.

**Payload sent to your URL:** identical to the `GET /v1/jobs/{job_id}` response above (same dp02 shape). The job identifier is `id` (not `job_id`), and it carries `"schema_version": "dp02"`.

```json
{
  "id": "550e8400-...",
  "status": "completed",
  "schema_version": "dp02",
  "pipeline": "standard",
  "document": {"page_count": 3, "content": {"format": "markdown", "text": "..."}},
  "extraction": {"fields": [{"key": "vendor", "value": "Acme Inc", "needs_review": false, "location": {"page": 1}}]},
  "review": {"needs_review": false, "fields_total": 20, "fields_needing_review": 0, "review_rate": 0.0, "flags": []},
  "artifacts": {"preview_url": "https://preview.deepread.tech/..."},
  "webhook": {"url": "https://yourapp.com/webhook", "delivered": true}
}
```

**Important:**
- Webhooks are **NOT authenticated** — always fetch the canonical result via `GET /v1/jobs/{job_id}` with your API key
- Must be HTTPS
- Return 2xx to confirm delivery
- Delivery is best-effort — use polling as fallback if webhook not received
- Make your endpoint idempotent (may receive duplicates)

---

## Rate Limits

Every response includes these headers:

| Header | Description |
|--------|-------------|
| `X-RateLimit-Limit` | Monthly pages in your plan |
| `X-RateLimit-Remaining` | Pages remaining this cycle |
| `X-RateLimit-Used` | Pages used this cycle |
| `X-RateLimit-Reset` | Unix timestamp when quota resets |

**Plans:**
| Plan | Pages/month | Max file | Per-doc limit | Rate limit |
|------|-------------|----------|---------------|------------|
| Free | 2,000 | 15 MB | 50 pages | 10 req/min |
| Pro ($99/mo) | 50,000 | 50 MB | Unlimited | 100 req/min |
| Scale | 1,000,000 | 50 MB | Unlimited | 500 req/min |

---

## Error Handling

All errors return:
```json
{"detail": "Human-readable error message"}
```

| Status | Meaning |
|--------|---------|
| 400 | Bad request — invalid schema, unsupported file, both schema + blueprint_id |
| 401 | Invalid or missing API key |
| 404 | Job not found |
| 413 | File too large for your plan |
| 429 | Rate limit or monthly quota exceeded |
| 500 | Server error |

**Quota exceeded (429):**
```json
{
  "detail": {
    "error": "page_count_exceeded",
    "message": "Document has 100 pages, exceeds 50-page limit for FREE plan. Upgrade to PRO.",
    "page_count": 100,
    "max_pages": 50,
    "plan": "free"
  }
}
```

**Common failure reasons in jobs:**
- Document issues: corrupted, unreadable, poor scan quality, processing timeout
- Schema issues: invalid JSON Schema, required fields not found
- Plan limits: file too large, too many pages, quota exceeded

---

## Code Examples

### Python

```python
import requests
import time
import json

API_KEY = "sk_live_YOUR_KEY"
BASE = "https://api.deepread.tech"

# Submit document with structured extraction
schema = {
    "type": "object",
    "properties": {
        "vendor": {"type": "string", "description": "Vendor or company name"},
        "total": {"type": "number", "description": "Total amount due"},
        "due_date": {"type": "string", "description": "Payment due date"}
    }
}

with open("invoice.pdf", "rb") as f:
    resp = requests.post(
        f"{BASE}/v1/process",
        headers={"X-API-Key": API_KEY},
        files={"file": f},
        data={"schema": json.dumps(schema)}
    )
job_id = resp.json()["id"]

# Poll with exponential backoff
delay = 5
while True:
    time.sleep(delay)
    result = requests.get(
        f"{BASE}/v1/jobs/{job_id}",
        headers={"X-API-Key": API_KEY}
    ).json()

    if result["status"] in ("completed", "failed"):
        break
    delay = min(delay * 1.5, 3

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [deepread-tech](https://github.com/deepread-tech)
- **Source:** [deepread-tech/skills](https://github.com/deepread-tech/skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** yes
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-deepread-tech-skills-api
- Seller: https://agentstack.voostack.com/s/deepread-tech
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
