StructuredWeb
Use cases

Six jobs.
One request, six schemas.

Nothing below needs a different product or a different endpoint. The only thing that changes between them is the shape you ask for — which is the point.

4 credits per URLSame endpoint every time
01Product and pricing teams

Competitive pricing sweeps

Twenty competitor pricing pages, twenty different layouts, one table at the end of it. Point a batch at the list weekly and diff the objects — the shape can't drift because the shape is yours.

THE SCHEMA
{
  "type": "object",
  "properties": {
    "plans": { "type": "array", "items": {
      "type": "object",
      "properties": {
        "name":     { "type": "string" },
        "monthly":  { "type": "number" },
        "annual":   { "type": "number" },
        "seats":    { "type": ["number", "null"] }
      },
      "required": ["name", "monthly"] } }
  },
  "required": ["plans"]
}
02Sales and RevOps

Lead enrichment from a website

You have a domain and nothing else. Get the industry, the headcount band, the tech they mention, the contact address and whether they publish pricing — straight into the CRM shape you already use.

THE SCHEMA
{
  "type": "object",
  "properties": {
    "industry":       { "type": "string" },
    "employee_band":  { "type": "string",
                        "enum": ["1-10","11-50","51-200","201-1000","1000+"] },
    "contact_email":  { "type": ["string", "null"] },
    "has_pricing_page": { "type": "boolean" }
  },
  "required": ["industry"]
}
03Marketplaces and resellers

Catalog and inventory sync

Supplier product pages become rows: SKU, title, price, currency, availability, image. Strict mode keeps a half-read page out of your catalog instead of writing a null price into it.

THE SCHEMA
{
  "type": "object",
  "properties": {
    "sku":          { "type": "string" },
    "title":        { "type": "string" },
    "price":        { "type": "number", "minimum": 0 },
    "currency":     { "type": "string", "minLength": 3, "maxLength": 3 },
    "in_stock":     { "type": "boolean" },
    "image_url":    { "type": "string" }
  },
  "required": ["sku", "title", "price", "currency"]
}
04Recruiters and market analysts

Job-board monitoring

Which roles is a company hiring, where, at what band, and remote or not. Run the same schema across fifty careers pages and you have a hiring signal instead of fifty tabs.

THE SCHEMA
{
  "type": "object",
  "properties": {
    "roles": { "type": "array", "items": {
      "type": "object",
      "properties": {
        "title":    { "type": "string" },
        "location": { "type": "string" },
        "remote":   { "type": "boolean" },
        "salary_min": { "type": ["number", "null"] },
        "apply_url":  { "type": "string" }
      },
      "required": ["title", "apply_url"] } }
  },
  "required": ["roles"]
}
05Developer-relations and integrations

Changelog and release tracking

Turn a vendor's release notes into versioned records with an added/fixed/changed split and a breaking flag, so a breaking change reaches your team as a row rather than as an outage.

THE SCHEMA
{
  "type": "object",
  "properties": {
    "releases": { "type": "array", "items": {
      "type": "object",
      "properties": {
        "version":  { "type": "string" },
        "date":     { "type": "string" },
        "breaking": { "type": "boolean" },
        "added":    { "type": "array", "items": { "type": "string" } }
      },
      "required": ["version"] } }
  },
  "required": ["releases"]
}
06Agent builders

A tool your agent can actually trust

An agent that scrapes gets a wall of markdown it has to re-read every turn. An agent with this gets the object it declared — and a valid flag telling it whether to proceed or ask for help. Over MCP it is one tool call.

THE SCHEMA
// MCP · extract_structured
{
  "url": "https://example.com/pricing",
  "schema": { "type": "object",
              "properties": { "price": { "type": "number" } },
              "required": ["price"] },
  "strict": true
}
Where it won't help

Worth knowing before you spend anything.

The extractor reads what a browser can reach without signing in. It is honest about the rest rather than returning a confident-looking empty object.

Pages behind a login

No session is carried, so a members-only page returns whatever the logged-out view shows. Not charged when that view is empty.

Facts that aren't on the page

A field the page never states comes back in missing_fields, not invented. That is deliberate: a plausible guess would pass validation and be wrong.

Very long documents

Only the first stretch of a page is read. For a book-length doc, point the schema at the specific section's URL rather than the index.

Bring your own schema.