AgentStack
SKILL verified MIT Self-run

Deepread Api

skill-deepread-tech-skills-api · by deepread-tech

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.

No reviews yet
0 installs
9 views
0.0% view→install

Install

$ agentstack add skill-deepread-tech-skills-api

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access Used
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Deepread Api? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

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

{"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):

{
  "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

{"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):

{
  "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".

{
  "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):

{
  "id": "550e8400-...",
  "status": "failed",
  "error": "PDF parsing failed: file may be corrupted"
}

Statuses: queuedprocessingcompleted 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.

{
  "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.

{
  "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

{
  "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:

{
  "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

{
  "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: pendinginitializingrunningcompleted, failed, or cancelled

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

Returns the optimized JSON schema after optimization completes.

Using a Blueprint

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".

{
  "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:

{"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):

{
  "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

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.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.