Resolve API v1
Turn one public HTTP or HTTPS resource into bounded, machine-readable web content, document text, structured data, plain text, or image metadata.
Updated September 8, 2026
Quickstart
AvailableUse Resolve when an agent has a public URL but cannot reliably consume it directly, such as a JavaScript-rendered page, PDF, CSV/JSON download, text resource, or image that needs metadata.
| Method | Path | Purpose | Auth / payment |
|---|---|---|---|
| POST | /v1/resolve | Resolve one public resource. | x402 payment required ($0.03 USDC). |
| GET | /v1/resolves/{id} | Read current state or result. | Job-scoped read token; no additional payment. |
| GET | /health | Service health. | None. |
| GET | /openapi.json | OpenAPI specification. | None. |
Resolve a resource
POST https://resolve.exende.dev/v1/resolve
The required url must point to a public HTTP or HTTPS resource. outputaccepts auto, markdown, text, or json.render accepts auto, always, or never.
bash
curl — initial request returns HTTP 402
curl -i -X POST \
https://resolve.exende.dev/v1/resolve \
-H "Content-Type: application/json" \
--data '{
"url": "https://example.com/report.pdf",
"output": "auto",
"render": "auto"
}'javascript
JavaScript — read the live x402 challenge
const endpoint = "https://resolve.exende.dev/v1/resolve";
const input = {
url: "https://example.com/article",
output: "auto",
render: "auto",
};
const response = await fetch(endpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(input),
});
if (response.status === 402) {
const challenge = response.headers.get("PAYMENT-REQUIRED");
// Give the live challenge to your x402 v2 client, then repeat
// this request with its PAYMENT-SIGNATURE header.
console.log(challenge);
}After a valid x402 payment, completed synchronous work returns HTTP 201. Recovery of an already-paid job that is still processing can return HTTP 202. Always build payment from the live 402 challenge instead of hardcoding the recipient or token contract.
json
Completed PDF result
{
"id": "resolve_0123456789abcdef0123456789abcdef",
"status": "completed",
"resource": {
"requested_url": "https://example.com/report.pdf",
"final_url": "https://example.com/report.pdf",
"content_type": "application/pdf",
"content_disposition": null,
"size_bytes": 123456,
"redirect_count": 0
},
"resolved": {
"type": "document",
"format": "pdf",
"text": "Example report text.",
"markdown": null,
"data": null,
"links": null
},
"metadata": {
"title": "Example report",
"pages": 12,
"text_available": true
},
"processing": {
"strategy": "pdf_text",
"browser_used": false,
"browser_ms_used": null,
"ocr_used": false,
"duration_ms": 840,
"cost_estimate_usd": "0.001100"
},
"limits": {
"truncated": false,
"output_bytes": 12345
},
"status_url": "https://resolve.exende.dev/v1/resolves/resolve_0123456789abcdef0123456789abcdef",
"read_token": "ex_resolve_read_..."
}Read a result
GET /v1/resolves/{id}
Creation returns a job-scoped read_token. Pass it as a Bearer token or inX-Resolve-Read-Token. Read responses never repeat the token and useCache-Control: private, no-store. Follow-up reads need no second Exende payment.
bash
Read current state or result
curl \
https://resolve.exende.dev/v1/resolves/resolve_0123456789abcdef0123456789abcdef \
-H "Authorization: Bearer ex_resolve_read_..."Formats and output
| Detected resource | Processing path | Normalized output |
|---|---|---|
| Static HTML | Bounded HTTP fetch and extraction | Text, Markdown, metadata, and links |
| Client-rendered HTML | Browser Run only when needed or requested | Rendered text, Markdown, metadata, and links |
| Deterministic text-layer parsing | Document text and page metadata | |
| JSON, CSV, XML, text | Format-specific bounded parsing | Structured data or normalized text |
| PNG, JPEG, GIF, WebP | Header and metadata inspection | Image format, dimensions, and MIME metadata |
Resolve v1 does not provide OCR, archive extraction, screenshots, DOCX/XLSX extraction, or LLM-based parsing.
x402 payment
One Resolve job costs $0.03 USDC using x402 v2, the exact scheme, and Base Mainnet (eip155:8453). The server returns HTTP 402 before resource probing. Reuse the same payment identifier only when recovering the same logical paid request; a changed request returns PAYMENT_IDENTIFIER_CONFLICT.
Security and limits
Resolve permits standard-port public HTTP and HTTPS targets only. It rejects embedded credentials, direct IP URLs, local/private/metadata hosts, internal Exende hosts, and DNS results that resolve to non-public addresses. Redirects are followed manually and every destination is revalidated. Browser document requests pass through the same public-target controls.
| Redirects | 3 maximum |
|---|---|
| Download | 10 MiB maximum |
| Output | 512 KiB maximum |
| Browser runtime | 30 seconds maximum |
| PDF pages | 500 maximum |
| Retention | 72 hours |
Additional v1 limits include 2 MiB HTML/text, 5 MiB CSV, 10 MiB PDF/image, a 100:1 decompression ratio, 250 content-bearing browser requests, four document navigations, 200 extracted links, and zero internal retries. Stored outcomes are encrypted and retained for 72 hours.
Errors
Every error uses a stable JSON envelope with error.code, error.message, and error.request_id. LIMIT_EXCEEDED can be 413 for bounded input/output limits or 502 for an invalid/excessive upstream redirect chain.
| HTTP | Code |
|---|---|
| 400 | INVALID_REQUEST |
| 400 | INVALID_URL |
| 400 | UNSUPPORTED_SCHEME |
| 400 | PRIVATE_NETWORK_BLOCKED |
| 400 | URL_NOT_ALLOWED |
| 404 | RESOURCE_NOT_FOUND |
| 502 | RESOURCE_FETCH_FAILED |
| 413 | RESOURCE_TOO_LARGE |
| 415 | UNSUPPORTED_FORMAT |
| 422 | PARSE_FAILED |
| 502 | RENDER_FAILED |
| 504 | TIMEOUT |
| 413 / 502 | LIMIT_EXCEEDED |
| 401 | INVALID_READ_TOKEN |
| 404 | RESOLVE_NOT_FOUND |
| 400 | PAYMENT_IDENTIFIER_REQUIRED |
| 409 | PAYMENT_IDENTIFIER_CONFLICT |
| 409 | PAYMENT_IN_PROGRESS |
| 503 | PAYMENT_RECONCILIATION_PENDING |
| 500 | INTERNAL_ERROR |
