Skip to content

Agent skill

Teach your agent Contrie in one paste.

contrie-web-extract is a single file your agent loads on demand. It covers setup, when to read a page and when to structure it, how to check an answer before using it, what each refusal means, and what a call costs.

Lines
490
Sections
15
Tokens, about
7,600

terminal

  1. Install the skill

    mkdir -p ~/.claude/skills/contrie-web-extract && \
    curl -fsSL https://www.contrie.com/agent-onboarding/SKILL.md \
      -o ~/.claude/skills/contrie-web-extract/SKILL.md
  2. Connect the tools

    claude mcp add --transport http contrie \
      https://www.contrie.com/mcp

    Then run /mcp, pick contrie and choose Authenticate. No API key needed.

  3. Give it a real job

    Use Contrie to get the latest version, release date and license of the requests package from https://pypi.org/project/requests/, and show me the page text behind each value.

    Your agent checks your account first (free). The answer is charged only if it clears the quality bar, and each value comes back with the passage it was found in.

The file

Read exactly what your agent will read.

This is the published file, not a summary. Pick a section to jump to it. The same bytes are served at /agent-onboarding/SKILL.md.

contrie-web-extract/SKILL.md
---
name: contrie-web-extract
description: Extract validated JSON or clean markdown from a single public web page using Contrie's hosted API or MCP server, with explicit acceptance, source evidence, grounded-value coverage and customer credits.
---
# Contrie web extraction
To install this skill, save this file as `<your skills directory>/contrie-web-extract/SKILL.md`:
the directory name matches `name` above.
Contrie turns one public URL into structured data or markdown. Check `success`
and validity before consuming structured output. The quality score describes
structure, field coverage and text support, not the probability of truth.
Markdown is ungraded. Final metadata includes source, credits, request progress
and grounding coverage. Supporting source excerpts are final evidence; the full
source corpus is not embedded. An absent grounding ratio is unmeasured.
Each request reads only the URL it names: a plain GET that follows up to 10 redirects (every hop
checked against private addresses, at most 10 MB read), a headless-browser load of that page when
rendering, or both. Links on the page are never followed. The plain fetch refuses a file whose
media type is PDF, image other than SVG, audio, video, font, archive or office, or whose first
bytes are a PDF, PNG, JPEG, GIF, TIFF, WebP, ZIP, legacy Office (OLE), gzip, bzip2, xz, MP3, WAV,
AVI, Ogg, FLAC, WebM, MP4/MOV or Windows executable signature, as `FETCH_FAILED` at 0 credits. A
browser render refuses a file served with one of those media types the same way, and one the
browser shows whose detected type or first bytes match; any other file the browser downloads
instead of showing ends as `RENDER_REQUIRED` at 0 credits. On the plain fetch, other binaries
under a generic label such as `application/octet-stream` are read as text.
Grounding answers *is this value present in this page*, never *does the page
say this about that*. A value that is correct for a different field still
reads as grounded: it bounds invention, not correctness. `metadata.binding`
partly closes that gap for numbers, dates and short digit-bearing values (see
step 3 of the decision procedure).
Acceptance counts it: at least half of all returned values (nulls excluded) must be
found in the page text (`groundingCoverage.grounded` at least half of `total`). Booleans
and strings under three characters are never found, so an answer made mostly of yes/no
values or one- or two-letter codes is refused. Ask for such a value as the text the page
shows (for example `"the stock status as shown"`), not as a boolean.
## Rendering
`render: "auto"` (default) can render eligible JavaScript shells; `"always"` requests browser-first acquisition and `"never"` disables it. Browser work is bounded by plan, capacity and deadlines. A rendered capture does not prove all content loaded; login walls and unsupported sources can still fail. A browser response of 401, 403, 429 or 451, or a recognized challenge still showing when an explicit `always` render completes, ends with 422 `SOURCE_REFUSED` at 0 credits (a usable 429 keeps `Retry-After`); other browser failures keep the bounded rendering fallback. Successful rendered answers add 2 credits.
## Evidence packets
Extraction responses with metadata report `metadata.evidenceStatus`. When it is `signed`,
`metadata.evidence` is a v2 Ed25519 seal over the complete public response
except the seal itself, including acceptance, source, trace, credits and the
final grounding excerpts. Hand the whole response to another agent or auditor;
they can verify it free at `POST /api/v1/evidence/verify` or offline with
`/evidence-verifier.mjs` and a separately obtained, pinned key set from
`GET /api/v1/evidence/keys`. A valid signature proves issuer-key possession and
response integrity, not field attribution, freshness or factual truth. Current packets omit
the internal source basis; `?refetch=true` reports source comparison unavailable. Older
packets with supported source metadata may allow a separate content comparison.
## Page reuse
`options.maxAge` (seconds) lets you accept a recently fetched copy of the
page from your own account instead of a live fetch; the response says so
(`metadata.cached`, `metadata.fetchedAt`, preserving the original fetch time).
Default 0 skips cache reads and writes. Use a short window for changing pages,
a longer window for reference docs, and 0 for a final freshness-sensitive check.
Reuse never exceeds 24 hours or a shorter origin expiry. URLs with query strings,
fragments or user information, and pages with restrictive cache headers or cookies,
are fetched live without entering the page cache. This is not a zero-retention
setting for extraction logs. A fresh fetch or valid receipt does not establish
that the fact represented by a page is still true.
## Monitors
`POST /api/v1/monitors` with `{ url, extract | schema, every?, webhookUrl? }`
turns a question into a standing watch. `every` is minutes between slots (default 60, minimum 15, maximum 10,080).
Contrie runs the baseline immediately, re-asks on
cadence slots that can be delayed or missed. Plans allow Free 3, Builder 25, Pro 100 active monitors.
Creation is not idempotent: after a lost response, list your monitors before retrying, or the retry
creates a second monitor that also charges. A change records before/after responses, their evidence status and a field diff. A configured webhook receives one signed POST attempt (secret shown once); delivery is not guaranteed.
The signature header is `X-Contrie-Signature: t=<unix seconds>,v1=<hex>`, where v1 is HMAC-SHA256 of
`t + "." + raw body` keyed by the webhook secret. Contrie enforces no timestamp tolerance: choose
one and reject deliveries older than it.
Read history with `GET /api/v1/monitors/{id}`. Every run with an accepted answer is charged like one
extraction, and runs keep going until you stop the monitor: an hourly monitor can make up to 24
charged runs a day. List yours with `GET /api/v1/monitors` or the `contrie_monitors {}` tool, and
stop one with `DELETE /api/v1/monitors/{id}` or `contrie_unwatch { id }` (no credits; history stays readable).
Stopping twice differs by transport: REST `DELETE` on an already stopped monitor returns 404
`NOT_FOUND`, while `contrie_unwatch` succeeds and returns the stopped monitor unchanged.
History returns 20 events at a time. If `nextCursor` is present, use it as
`GET /api/v1/monitors/{id}?before=EVENT_ID` or `contrie_changes { id, before }`.
Keep webhook `eventId` for exact recovery with `?eventId=EVENT_ID` or
`contrie_changes { id, eventId }`; older webhooks may omit the ID. Do not combine
selectors. Unknown or foreign IDs return `NOT_FOUND`; combining `before` and `eventId`, or an empty or non-UUID value, returns 400 `INVALID_REQUEST`. History remains readable
after stopping; reading it consumes account RPM but no extraction credits.
Deduplicate by event ID because history changes while paging. Verify the original
before/after packets, compare source acquisition times and inspect the excerpts
before acting. A changed extracted value is not proof that a source fact changed;
signatures establish integrity, not semantic correctness. Preserve the raw webhook
body when verifying its signature, including any added eventId field.
## When to use this skill
- You need structured JSON from a page and can describe the fields in
natural language or a JSON Schema.
- You need the readable content of a page as clean markdown, cheaply.
- You need inspectable structure/text checks before deciding how to use an extraction.
## When NOT to use this skill
- Crawling a site or following links — Contrie extracts one page per call.
- Searching the web — there is no search endpoint.
- Multi-step browser tasks (clicking, filling forms, logging in) — Contrie
does not drive a browser session.
- Pages behind a login wall — no session/cookie support.
## Setup
### MCP (hosted, Streamable HTTP) — no API key
Point your client at the URL with no credential, then sign in through your client
(Claude Code: `/mcp`, pick contrie, Authenticate; claude.ai: Customize → Connectors →
Add → Add custom connector, Authentication "Sign in when needed"). An unauthorized tool
call is answered with an OAuth 2.1 protected-resource challenge. Verified end to end:
Claude Code (2026-09-21), a claude.ai custom connector (2026-09-24), and Codex CLI
0.157.1 with an existing Free account (2026-09-27). Other clients'
OAuth flows, including Claude Desktop's, are not yet verified. Clients that accept a custom
Authorization header (Claude Code, Codex, Cursor) can use an API key instead.
For Claude Code's `.mcp.json` (remote servers require `type: "http"`):
```json
{
"mcpServers": {
"contrie": {
"type": "http",
"url": "https://www.contrie.com/mcp"
}
}
}
```
Claude Code, in one command:
```bash
claude mcp add --transport http contrie https://www.contrie.com/mcp
```
contrie shows "Needs authentication": run `/mcp`, pick contrie and choose
Authenticate, or run `claude mcp login contrie`.
Codex CLI (commands checked with 0.157.1):
```bash
codex mcp add contrie --url https://www.contrie.com/mcp
codex mcp login contrie --scopes contrie:account,offline_access
```
Skip the add command when the server is already configured. OAuth does not also
need an API key, including on Free. Confirm the browser account before approving.
Codex uses `~/.codex/config.toml`, not the Claude JSON above; see
https://www.contrie.com/docs/mcp#codex for its config and API-key alternative.
These commands do not establish that a running conversation has reloaded its
connection. On 2026-09-27 an existing Free account completed browser approval,
account and verification checks, a live page read and unchanged request replay
through Codex with no API key configured. Automatic token refresh and fresh
signup were not exercised.
After approval, call `contrie_account {}` (zero extraction credits), then try
`contrie_read {"url":"https://example.com/","render":"never"}` for a live page
read (1 credit on success). Tool discovery alone is not proof of account access.
If a conversation still says Authentication required, reconnect/reload its MCP
connection. In Claude Code: `/mcp` → contrie → Reconnect; Authenticate or
Re-authenticate if offered. In Codex, use the login command above when needed,
then reload the connection; if no reload action is available, restart the client
and resume the conversation or start a new session. If refresh fails, sign in
again. For claude.ai/Claude Desktop, reconnect in connector settings.
To switch accounts, run `codex mcp logout contrie` or
`claude mcp logout contrie`, choose the intended account in the next browser
sign-in, then reconnect and check the account. A retained browser login may need
sign-out first. When changing from a key to OAuth, remove the old credential
source from this server's config; it can override the new sign-in. When changing
to a helper-provided key, clear stored OAuth first. Do not delete an account or
revoke unrelated keys. Clearing local credentials does not immediately revoke
issued tokens everywhere. Full recovery: https://www.contrie.com/docs/mcp#connection-recovery.
After authentication recovers, retain an interrupted extract/read's original
inputs and idempotencyKey; do not silently replace the request identity.
### API key — headless, CI and the REST API
OAuth sign-in needs browser approval; API keys are the straightforward unattended
CI/server alternative, and `/api/v1/*` is built for keys. Get one at https://www.contrie.com/dashboard/keys (human sign-up;
skip this for the sample URLs below). Store it as an environment variable, never
inline in a prompt or URL:
```bash
export CONTRIE_API_KEY=ck_live_...
```
Claude Code `.mcp.json`, as an alternative to the OAuth configuration above:
```json
{
"mcpServers": {
"contrie": {
"type": "http",
"url": "https://www.contrie.com/mcp",
"headers": { "Authorization": "Bearer ${CONTRIE_API_KEY}" }
}
}
}
```
Tools exposed: `contrie_extract { url, extract?, schema?, maxAge?, render?, idempotencyKey? }` returns JSON.
`contrie_read { url, maxAge?, render?, idempotencyKey? }` returns the full REST-shaped JSON response in an MCP
text block (`data: null`, `markdown`, metadata/evidence; a successful read costs 1 credit and a failed one 0, and a successful rendered read adds 2).
The REST-only options `format: "both"`, `options.timeout` and `options.waitFor` are not MCP tool arguments. `contrie_verify { data, url | html |
text }` checks data you already have against its source page — no credits charged; with `html`, add `baseUrl` to resolve relative links.
`contrie_watch` creates a monitor; `contrie_changes { id }` retrieves its changes; `contrie_monitors {}`
lists your active monitors; `contrie_unwatch { id }` stops one. `contrie_account {}` reads your
credits and restrictions. Listing, changes, stopping and the account check charge no
credits. Eight tools are hosted.
An operator-enabled pilot adds `contrie_check_fields` and `contrie_verification`
only when the server lists them. Use the first with
`{idempotencyKey: UUIDv4, source:{url,html}, contract:{version:1,fields}, proposedData?}`
to check explicit entity/property/context relationships in HTML you already hold.
It does not fetch its descriptive URL; `contrie_read` markdown is not original HTML.
Keep the UUID and exact input for safe retry. It returns `{run,dashboardUrl}`;
inspect `run.state` and `run.result.status`, `data`, and field decisions. A completed
refusal with withheld data is a usable result, not an operational `isError`.
`contrie_verification {executionId}` recovers; `{}` lists 25 runs and `{before:nextCursor}`
continues history. Never combine ID and cursor. Shared workspace pilot limits apply;
no extraction credits, including recovery at zero balance. Payloads last seven days,
content-free retry identities 30 days. A source signature proves integrity, not
authenticity, freshness or factual truth. Tools cannot write human labels. Use the
same Contrie account to open `dashboardUrl`. Full example and bearer REST equivalent:
https://www.contrie.com/docs/workspace#agent-workflow.
Without any credential, clients can initialize and list tools, but only an exact recorded
`contrie_extract` request below succeeds. Other tool calls, and invalid, expired
or revoked presented API keys, receive an HTTP 401 OAuth challenge. OAuth access requires a signed JWT bound to the configured issuer, audience `https://www.contrie.com/mcp` and `contrie:account` capability. Identity-only scopes get 403 and opaque tokens are refused. Verified end to end on 2026-09-21 with an independent client. Point your client at the URL with no credential, then sign in through your client (Claude Code: `/mcp`, pick contrie, Authenticate); an API key stays available for headless use. JWT revocation is not immediate.
### curl fallback (no MCP client available)
This sample request needs no key and runs as printed, as a dry run before wiring up auth:
```bash
curl -X POST https://www.contrie.com/api/v1/scrape \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "extract": "Extract the page title, heading, and all paragraph text"}'
```
For live work, change the request and add `-H "Authorization: Bearer $CONTRIE_API_KEY"`.
A sample request sent with a key is live work and is charged like any other.
Sample URLs work without a key, and each answers ONLY its recorded request —
the exact prompt below, JSON format, no schema. Send anything else and it is a
live extraction that needs authentication (the error says so):
`https://news.ycombinator.com`, `https://example.com`,
`https://github.com/trending`, `https://www.contrie.com/pricing`. Their recorded prompts:
`"Get the top 5 stories with title, URL, and points"`,
`"Extract the page title, heading, and all paragraph text"`,
`"Get the top 5 trending repositories with name, description, language, and stars"`,
`"Each plan with its monthly price in USD and included monthly credits"`.
More recordings were asked with a JSON Schema and replay only when the request
carries that exact schema as well as the exact prompt; `/llms.txt` lists the schemas.
They are the dry run for schema mode, and their metadata includes `requestedFields`:
`https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html` with `"The product name and its current price"`, and
`https://quotes.toscrape.com/` with `"Only the first 3 quotes on the page"`, and
`https://github.com/trending/rust?since=weekly` with `"The top 10 trending repositories this week, in page order, with total stars, forks and stars gained this week"`,
`https://en.wikipedia.org/wiki/List_of_tallest_buildings` with `"The five tallest buildings in rank order, with city, country, height in metres, floors and year completed"`,
`https://arxiv.org/abs/1602.03837` with `"The citation details of this paper: title, authors, submission date, journal reference, DOI and primary subject"`,
`https://pypi.org/project/requests/` with `"The package name, latest version, release date, license, required Python version and one-line summary"`,
`https://en.wikipedia.org/wiki/Stripe,_Inc.` with `"The company profile from the infobox: name, industries, year founded, founders, headquarters, revenue and number of employees"`,
`https://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html` with `"Every euro foreign exchange reference rate on the page, with the date they apply to"`.
## Decision procedure
1. **Reading vs. structuring.** If the goal is to read or summarize a page,
use `format: "markdown"` — readable output costs 1 credit
before any rendering surcharge and has `qualityScoreKind: "not_applicable"`. If downstream code depends on a specific shape, use `schema`
instead of `extract`, declare mandatory fields in `required`, and check `success`
before consuming the answer. For structured output, `success: true` already means
`metadata.valid` is true and the quality score is at least 70; the other fields explain a
refusal and scope an accepted answer, they are not a second gate. Rejected candidates are not usable output.
2. **Natural language vs. schema.** Prefer `extract` (a plain-English
description) for exploratory or one-off pulls. Prefer `schema` (JSON
Schema: `object`/`array`/`string`/`number`/`integer`/`boolean`,
`properties`, `required`, `items`, `enum`, `description`) whenever the
caller parses the result programmatically. Unsupported keywords are carried
unchecked; a local `$ref` is inlined and a nullable `anyOf` becomes a type list.
Only unusable schemas are refused, with a 400 naming the keyword. Unknown fields
in a scrape or extract body are refused with a 400 that names them.
3. **Checking the result.** Check `success` first. For structured output, inspect
`metadata.valid`, `metadata.schemaValid` (when a schema was supplied), and requested-field coverage. Success requires local validation, a score of
at least 70, all declared schema properties returned in each applicable
object and array item, including optional properties, and at least half of all
returned values found in the page text. `metadata.requestedFields`
reports total/returned leaf counts and up to 50 missing paths. Use nullable
types for values that may be unavailable: explicit `null` acknowledges the field
but lowers `metadata.completeness`, the populated fraction. Extra fields cannot
compensate for omissions. These checks do not establish semantic correctness,
the number of matching source items, or completeness against a natural-language
request. Requested-field coverage is absent when no declared shape is measured.
- A high score alone does not establish that validation passed. After checking
success/validity, use grounding coverage to inspect text support and verify field meaning.
- Low score: inspect missing fields and source availability before changing the
request. The score alone does not diagnose the cause; a new call can cost resources.
- Refused (`success: false`, `RESULT_NOT_ACCEPTED`): a refusal carries no `groundingFields`
or values. Read `metadata.requestedFields.missing` and `metadata.groundingCoverage` (at
least half of returned values must be found), then retry once with nullable fields, values
asked for as the page writes them, or fewer fields.
- Low grounding on an accepted answer (`success: true`): read
`groundingFields` and treat each `grounded: false` entry as UNCONFIRMED,
not as wrong: the value may be absent, or it may be presented differently
in the page than in the result. Inspect those `path`s first, and retry
with a narrower `extract` only where inspection suggests a real miss. The
`excerpt` on each grounded entry is the audit trail for a human check.
- Binding conflicts: an accepted model answer from a current deployment
carries `metadata.binding` (`judged`, `conflicts: [{ path }]`, `truncated`);
recordings and responses stored before 2026-09-28 lack it, and absence
means no check ran. Each conflict `path` is a field whose value is on the
page, but the passages about that field state a different value. Treat those
fields as UNCONFIRMED and inspect them before use; the rest of the answer
stands. It is not a truth claim and changes neither acceptance nor credits.
`judged: 0` means no field could be checked, not that all passed;
`truncated: true` means some values were not judged.
4. **RENDER_REQUIRED.** Inspect whether rendering was disabled, unavailable or
attempted. An eligible request may use auto/always rendering or supplied HTML;
do not loop unchanged or assume a login wall is supported.
5. **Credits.** `metadata.credits` reports this extraction's customer consumption.
Rejected structured results cost 0; accepted structured output costs 1, 3, 8 or 15
credits before a successful rendering surcharge. Charges and source support
depend on the request and available account capacity.
6. **Data from somewhere else.** To check data you did not get from Contrie —
another extractor's output, your own scrape, a stored record — send it to
`POST /api/v1/verify` (or the `contrie_verify` tool) with the page. It runs
the same grounding check. For the same data/source bytes it is deterministic and
charges no credits. Contrie's own signed extractions carry text-support
evidence inline, but you still need to inspect attribution, freshness and
factual meaning for consequential use.
## Request and result example
This is an excerpt of the recorded answer the keyless sample replays, not a complete
signed packet. Exact recorded calls return historical provenance and zero current
credits. With no schema the requested fields are not counted (`coverageMeasured: false`),
so the score is at most 80.
```json
{ "url": "https://example.com", "extract": "Extract the page title, heading, and all paragraph text" }
```
```json
{
"success": true,
"data": { "title": "Example Domain", "heading": "Example Domain" },
"metadata": {
"qualityScore": 80,
"valid": true,
"coverageMeasured": false,
"grounding": 1,
"credits": 0,
"source": { "mode": "recording" },
"trace": [{ "stage": "complete", "detail": "Request complete" }]
}
}
```
## Streaming and recovery
Set `Accept: application/x-ndjson` on a live extraction to receive progress then a
terminal result or error. The compatibility event name is `trace`; the only public
stages are `loading`, `processing` and `complete`, with fixed display labels.
Check the final `success`, not the HTTP 200 of an already-open stream. Handle
chunk boundaries, a final line without a newline, cancellation and premature
connection closure. A progress event contains no partial answer.
On authenticated non-streaming JSON calls, `Idempotency-Key` binds the account,
operation and inputs. Use 8–200 visible ASCII characters. An identical request can
replay its retained response for 24 hours without new extraction work. HTTP 409
covers in-progress, changed-input, expired or unknown outcomes. Do not silently
use a new key after an unknown outcome: it deliberately authorizes new work.
Hosted `contrie_extract`
and `contrie_read` accept an optional `idempotencyKey` argument with the same
24-hour recovery behavior. Save the original arguments and reuse them unchanged
after an interrupted response. Recovery returns the retained response. A signed
response whose fields are all still public comes back unchanged, original signature
included; otherwise it comes back narrowed to the current public contract and
unsigned (`evidenceStatus: "unavailable"`, or `"not_issued_for_rejected_result"` for a rejected answer). Either way it keeps the original source
time and charge, and it does not refresh the page or charge again. Check the MCP
`isError` flag and embedded decision even on replay. Refresh your client's tool
inventory after an update. Streaming and monitor creation do not support this
caller retry identity. Calls without it remain separate work.
Recordings are anonymous, exact sample requests. Presenting authentication or
explicit acquisition options requests live work instead; never count a recorded
response as an external live extraction.
## Limits and errors
The Free allowance is 200 credits a month and 10 requests/minute per account (across all of its keys).
All plans: Free 200, Builder 10,000, Pro 40,000 credits a month; Free 10, Builder 30, Pro 100 requests per minute.
Each plan caps one request's credits, rendering included: Free 3, Builder 5, Pro 17. An answer above
the cap, or above the account's remaining credits, is refused as 429 `INFERENCE_BUDGET_EXCEEDED` at
0 credits, and the message says so; ask for fewer or simpler fields, or render "never".
Available service capacity is also required. Quota alone does not guarantee an answer.
Free service capacity is funded again each calendar month (UTC) from a shared monthly pool.
A month whose pool is already spent grants nothing further until the next one, so the next
month is a likely but not a guaranteed remedy. Check account status once when connecting or
after a capacity refusal; do not poll it, and do not assume a new key removes that refusal.
Source HTML/text is limited to 5,000,000 UTF-8 bytes; serialized schemas to 10,000
UTF-8 bytes; `extract` to 4,000 characters. The hosting platform can reject a combined body sooner.
Contrie reads at most the first 100,000 characters of a page's markdown, for extraction and
markdown alike; `metadata.evidenceCoverage.sourceTruncated` is true when it cut.
Monthly prices (USD): Free $0, Builder $19, Pro $79. On an active paid subscription, overage is
on by default at $2 per 1,000 credits, up to a monthly spending limit of $20 unless raised;
requests stop at that limit. Free has no overage. See https://www.contrie.com/pricing.
Errors have `{success:false,error:{code,message}}`. Read the status, code and
`Retry-After` when present. Over MCP there are no headers: an origin rate limit arrives as `SOURCE_REFUSED`
with no wait (by design, the wait is a REST header or nothing), so use a bounded backoff, for example
30 s then 2 min, before one or two retries. 400 means invalid input; 401/403 means authentication
or permission; 422 covers an unsupported or inaccessible source; 429 means a
request or account limit; 503 means temporarily unavailable service. A refused
structured answer is not a result to consume. Avoid repeated unchanged retries: a
`FETCH_FAILED` caused by a missing page (404 or 410), a page over 10 MB or more than 10
redirects fails the same way every time, so check the URL instead.
## References
- https://www.contrie.com/docs/scrape
- https://www.contrie.com/docs/extract
- https://www.contrie.com/docs/streaming
- https://www.contrie.com/docs/evidence
- https://www.contrie.com/docs/verify
- https://www.contrie.com/docs/rate-limits
- https://www.contrie.com/docs/errors
- https://www.contrie.com/openapi.json
## Before starting or repeating live work
Call `contrie_account {}` or `GET https://www.contrie.com/api/v1/account/status` with your bearer credential. The own-account response includes actual used, reserved and unreserved included credits, the UTC reset and high-level restrictions. It costs zero extraction credits and allocates no funds. A positive result is advisory, not a capacity reservation or price quote; the submitted request still checks source and service limits. Free service capacity is funded again each calendar month (UTC); within a month whose shared pool is spent, unused credits alone do not guarantee service. Respect restrictions and avoid a polling loop; a replacement API key does not bypass an account restriction.
## First live job: one product name and price
Use this request. Replace the example URL with an accessible page showing one product, its price and currency. Call `contrie_account {}` first to inspect current restrictions. Then call `contrie_extract` with `url` and this `schema` (hosted MCP accepts `maxAge: 0`), or POST the body below to `/api/v1/scrape` with your bearer credential and a new `Idempotency-Key`.
<!-- product-job-example:start -->
```json
{
"url": "https://your-store.example/product",
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"offers": {
"type": "object",
"properties": {
"price": {
"type": "number"
},
"priceCurrency": {
"type": "string"
}
},
"required": [
"price",
"priceCurrency"
],
"additionalProperties": false
}
},
"required": [
"name",
"offers"
],
"additionalProperties": false
},
"options": {
"maxAge": 0
}
}
```
<!-- product-job-example:end -->
Require `success: true` and `metadata.valid: true`. Compare the returned `name`, `offers.price` and `offers.priceCurrency` to the displayed product, not merely any matching text. Review original source time and partial-source limitations. Keep the signed response unchanged for verification when available. To check later, create a new request identity; use the old identity only for response recovery. Create a monitor for this same question only after the result is useful; monitor runs also require credits and current service capacity.

Never paste an API key into a skill or an agent chat; the skill tells your agent to read it from CONTRIE_API_KEY. Prefer the full reference? For Agents