Getting started
Manifest API makes any webpage agent-readable. Pass a URL, get back a structured JSON manifest describing what the page contains and what actions are available.
country (optional) — ISO 3166-1 alpha-2 code (e.g. "US", "DE"). Sets the scan's Accept-Language header, and for some sites, an additional locale cookie — best-effort steering of server-side geo/locale redirects, not a guarantee. Check locale_mismatch in the response either way.
Geo/locale honesty, not correction. Some sites redirect based on IP, headers, or a stored locale — Manifest doesn't attempt to override this universally or convert prices. country improves the odds of landing on the right locale for sites we've mapped, but for others it has no effect (and rarely, can even shift which wrong locale you get). locale_mismatch is the field to trust: if it's true, treat prices, availability, and copy on that page as locale-specific, not the one you asked for.
Authentication
All requests require an API key passed in the X-API-Key header. Keys are issued from your dashboard and can be rotated or revoked at any time.
X-API-Key: your-key-here
Requests without a valid key return
401 Unauthorized.
Endpoints
POST/manifest
Returns a structured action manifest for any URL.
Request:
JSON
{
"url": "https://example.com"
}
Response:
JSON
{
"url": "string",
"authenticated_user": "string | null",
"current_page_state": "string",
"actions": [
{
"id": "string",
"label": "string",
"type": "button | input | textarea | select | checkbox | radio | other",
"description": "string",
"required": "boolean",
"requires": [["string"]]
}
],
"navigation": [
{ "label": "label", "url": "string" }
],
"fingerprint": "string",
"cache_status": "hit | miss",
"captured_at": "ISO-8601 timestamp",
"expires_at": "ISO-8601 timestamp"
}
POST /fingerprint
GET /fingerprint?url=
Returns a stable hash of a page's interactive surface — no LLM call, never cached. Use it to cheaply check whether a page's actions have changed since your last /manifest call, before paying for a new manifest generation.
Request:
bash
curl -X POST https://manifest.omfang.io/fingerprint \ -H "X-API-Key: your-key" \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com"}'
Or as a GET:
bash
curl "https://manifest.omfang.io/fingerprint?url=https://example.com" \ -H "X-API-Key: your-key"
Response:
JSON
{ "url": "https://example.com", "fingerprint": "a3f5c9e1..." }
fingerprint is a SHA-256 hex digest computed from the page's interactive elements (role, name, input type). It's stable across unrelated layout shifts and DOM reordering — an ad or news ticker inserted earlier in the page won't change it — but it changes the moment a button, field, or link is added, removed, or renamed.
Every /manifest response also includes this same field, so you can compare a manifest you already fetched against a later /fingerprint call without re-running the full pipeline:
JSON
{ "url": "https://example.com", "actions": [ ... ], "fingerprint": "a3f5c9e1..." }
When to use it
If you're polling a page you've already generated a manifest for — waiting for a form to appear, checking whether a checkout flow changed — call /fingerprint on a short interval instead of /manifest. Only re-fetch the full manifest when the hash changes. This skips the LLM translation step entirely, so it's far cheaper per call than /manifest.
Limits
/fingerprint has its own monthly quota, separate from /manifest — exhausting one never blocks the other.
Rate limits (requests/minute) are shared with /manifest per plan.
SDK
python
fp = client.fingerprint(
"https://example.com"
)
print(fp.url, fp.fingerprint)
# or compare against an existing manifest
manifest =client.get(
"https://example.com"
)
if manifest.fingerprint != client.fingerprint(
"https://example.com"
).fingerprint:
manifest =client.get(
"https://example.com", fresh=True)
GET/health
Returns the API health status. No authentication required.
JSON
{ "status": "ok" }
GET/session-status
Returns whether the current browser session is valid. No authentication required
JSON
{ "valid": true }
or
JSON
{ "valid": false, "message": "Session expired" }
Response fields:
Field
Type
Description
url
string
The url that was requested
authenticated_user
string or null
Detected logged-in user, if any
current_page_state
string
Brief description of the page
actions
array
Interactive elements on the page
navigation
array
Primary navigation links
fingerprint
string
SHA-256 hash of the page's interactive surface — see /fingerprint
cache_status
"hit" | "miss"
Whether this response came from cache or a live scan
requested_country
string or null
The country param you sent, echoed back. null if not provided.
served_locale
string or null
Best-effort detected locale of the page actually captured (e.g. "en-DE"). null if no locale signal was found.
locale_mismatch
boolean
true if you requested a country and the page served a different locale — the site geo-routed elsewhere despite the request. false if they matched, or if no country was requested.
captured_at
ISO-8601 timestamp
When the page was actually scanned
expires_at
ISO-8601 timestamp
When this cached manifest expires
Action fields:
Field
Type
Description
id
string
Unique identifier for the action
label
string
Human-readable label
type
string
button, input, textarea, select, checkbox, radio, other
description
string
What the action does
required
boolean
Whether the field is required
requires
array of arrays of strings | omitted
Rate limits
Plans
Calls/month
Per-minute limit
Free
50
10/min
Starter
1,000
10/min
Pro
5,000
10/min
Exceeding the per-minute limits returns
429 Too Many Requests
Error codes
Code
Meaning
401
Missing or invalid API key
429
Rate limit exceeded
503
Browser session unavailable — retry later
Cache & Freshness
Manifest caches page extractions for 6 hours to keep repeated requests fast and cheap. Every response tells you exactly how fresh that data is:
Field
Type
Description
cache_status
"hit" | "miss"
Whether this response came from cache or a live scan
captured_at
ISO-8601 timestamp
When the page was actually scanned
expires_at
ISO-8601 timestamp
When this cached manifest expires (captured_at + 6h)
By default, requests may return a cached manifest up to 6 hours old. If your workflow involves forms, pricing, inventory, or any destructive action, pass fresh=true to bypass the cache and force a live scan — this counts as one billable API call.
JSON
// Request
POST /manifest
{ "url": "https://example.com/checkout", "fresh": true }
// Response
{
"cache_status": "miss",
"captured_at": "2026-07-26T14:32:07Z", "expires_at": "2026-07-26T20:32:07Z", "current_page_state": { ... }, "actions": [ ... ]
}
Rule of thumb: use the default cache for read-heavy or exploratory calls. Use fresh=true whenever the agent is about to submit a form, complete a purchase, or take any action where a stale DOM could cause a bad outcome.