1---
2name: contrie-web-extract
3description: 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.
4---
5
6# Contrie web extraction
7
8To install this skill, save this file as `<your skills directory>/contrie-web-extract/SKILL.md`:
9the directory name matches `name` above.
10
11Contrie turns one public URL into structured data or markdown. Check `success`
12and validity before consuming structured output. The quality score describes
13structure, field coverage and text support, not the probability of truth.
14Markdown is ungraded. Final metadata includes source, credits, request progress
15and grounding coverage. Supporting source excerpts are final evidence; the full
16source corpus is not embedded. An absent grounding ratio is unmeasured.
17
18Each request reads only the URL it names: a plain GET that follows up to 10 redirects (every hop
19checked against private addresses, at most 10 MB read), a headless-browser load of that page when
20rendering, or both. Links on the page are never followed. The plain fetch refuses a file whose
21media type is PDF, image other than SVG, audio, video, font, archive or office, or whose first
22bytes are a PDF, PNG, JPEG, GIF, TIFF, WebP, ZIP, legacy Office (OLE), gzip, bzip2, xz, MP3, WAV,
23AVI, Ogg, FLAC, WebM, MP4/MOV or Windows executable signature, as `FETCH_FAILED` at 0 credits. A
24browser render refuses a file served with one of those media types the same way, and one the
25browser shows whose detected type or first bytes match; any other file the browser downloads
26instead of showing ends as `RENDER_REQUIRED` at 0 credits. On the plain fetch, other binaries
27under a generic label such as `application/octet-stream` are read as text.
28
29Grounding answers *is this value present in this page*, never *does the page
30say this about that*. A value that is correct for a different field still
31reads as grounded: it bounds invention, not correctness. `metadata.binding`
32partly closes that gap for numbers, dates and short digit-bearing values (see
33step 3 of the decision procedure).
34
35Acceptance counts it: at least half of all returned values (nulls excluded) must be
36found in the page text (`groundingCoverage.grounded` at least half of `total`). Booleans
37and strings under three characters are never found, so an answer made mostly of yes/no
38values or one- or two-letter codes is refused. Ask for such a value as the text the page
39shows (for example `"the stock status as shown"`), not as a boolean.
40
41## Rendering
42
43`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.
44
45## Evidence packets
46
47Extraction responses with metadata report `metadata.evidenceStatus`. When it is `signed`,
48`metadata.evidence` is a v2 Ed25519 seal over the complete public response
49except the seal itself, including acceptance, source, trace, credits and the
50final grounding excerpts. Hand the whole response to another agent or auditor;
51they can verify it free at `POST /api/v1/evidence/verify` or offline with
52`/evidence-verifier.mjs` and a separately obtained, pinned key set from
53`GET /api/v1/evidence/keys`. A valid signature proves issuer-key possession and
54response integrity, not field attribution, freshness or factual truth. Current packets omit
55the internal source basis; `?refetch=true` reports source comparison unavailable. Older
56packets with supported source metadata may allow a separate content comparison.
57
58## Page reuse
59
60`options.maxAge` (seconds) lets you accept a recently fetched copy of the
61page from your own account instead of a live fetch; the response says so
62(`metadata.cached`, `metadata.fetchedAt`, preserving the original fetch time).
63Default 0 skips cache reads and writes. Use a short window for changing pages,
64a longer window for reference docs, and 0 for a final freshness-sensitive check.
65Reuse never exceeds 24 hours or a shorter origin expiry. URLs with query strings,
66fragments or user information, and pages with restrictive cache headers or cookies,
67are fetched live without entering the page cache. This is not a zero-retention
68setting for extraction logs. A fresh fetch or valid receipt does not establish
69that the fact represented by a page is still true.
70
71## Monitors
72
73`POST /api/v1/monitors` with `{ url, extract | schema, every?, webhookUrl? }`
74turns a question into a standing watch. `every` is minutes between slots (default 60, minimum 15, maximum 10,080).
75Contrie runs the baseline immediately, re-asks on
76cadence slots that can be delayed or missed. Plans allow Free 3, Builder 25, Pro 100 active monitors.
77Creation is not idempotent: after a lost response, list your monitors before retrying, or the retry
78creates 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.
79The signature header is `X-Contrie-Signature: t=<unix seconds>,v1=<hex>`, where v1 is HMAC-SHA256 of
80`t + "." + raw body` keyed by the webhook secret. Contrie enforces no timestamp tolerance: choose
81one and reject deliveries older than it.
82Read history with `GET /api/v1/monitors/{id}`. Every run with an accepted answer is charged like one
83extraction, and runs keep going until you stop the monitor: an hourly monitor can make up to 24
84charged runs a day. List yours with `GET /api/v1/monitors` or the `contrie_monitors {}` tool, and
85stop one with `DELETE /api/v1/monitors/{id}` or `contrie_unwatch { id }` (no credits; history stays readable).
86Stopping twice differs by transport: REST `DELETE` on an already stopped monitor returns 404
87`NOT_FOUND`, while `contrie_unwatch` succeeds and returns the stopped monitor unchanged.
88History returns 20 events at a time. If `nextCursor` is present, use it as
89`GET /api/v1/monitors/{id}?before=EVENT_ID` or `contrie_changes { id, before }`.
90Keep webhook `eventId` for exact recovery with `?eventId=EVENT_ID` or
91`contrie_changes { id, eventId }`; older webhooks may omit the ID. Do not combine
92selectors. 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
93after stopping; reading it consumes account RPM but no extraction credits.
94Deduplicate by event ID because history changes while paging. Verify the original
95before/after packets, compare source acquisition times and inspect the excerpts
96before acting. A changed extracted value is not proof that a source fact changed;
97signatures establish integrity, not semantic correctness. Preserve the raw webhook
98body when verifying its signature, including any added eventId field.
99
100## When to use this skill
101
102- You need structured JSON from a page and can describe the fields in
103 natural language or a JSON Schema.
104- You need the readable content of a page as clean markdown, cheaply.
105- You need inspectable structure/text checks before deciding how to use an extraction.
106
107## When NOT to use this skill
108
109- Crawling a site or following links — Contrie extracts one page per call.
110- Searching the web — there is no search endpoint.
111- Multi-step browser tasks (clicking, filling forms, logging in) — Contrie
112 does not drive a browser session.
113- Pages behind a login wall — no session/cookie support.
114
115## Setup
116
117### MCP (hosted, Streamable HTTP) — no API key
118
119Point your client at the URL with no credential, then sign in through your client
120(Claude Code: `/mcp`, pick contrie, Authenticate; claude.ai: Customize → Connectors →
121Add → Add custom connector, Authentication "Sign in when needed"). An unauthorized tool
122call is answered with an OAuth 2.1 protected-resource challenge. Verified end to end:
123Claude Code (2026-09-21), a claude.ai custom connector (2026-09-24), and Codex CLI
1240.157.1 with an existing Free account (2026-09-27). Other clients'
125OAuth flows, including Claude Desktop's, are not yet verified. Clients that accept a custom
126Authorization header (Claude Code, Codex, Cursor) can use an API key instead.
127
128For Claude Code's `.mcp.json` (remote servers require `type: "http"`):
129
130```json
131{
132 "mcpServers": {
133 "contrie": {
134 "type": "http",
135 "url": "https://www.contrie.com/mcp"
136 }
137 }
138}
139```
140
141Claude Code, in one command:
142
143```bash
144claude mcp add --transport http contrie https://www.contrie.com/mcp
145```
146
147contrie shows "Needs authentication": run `/mcp`, pick contrie and choose
148Authenticate, or run `claude mcp login contrie`.
149
150Codex CLI (commands checked with 0.157.1):
151
152```bash
153codex mcp add contrie --url https://www.contrie.com/mcp
154codex mcp login contrie --scopes contrie:account,offline_access
155```
156
157Skip the add command when the server is already configured. OAuth does not also
158need an API key, including on Free. Confirm the browser account before approving.
159Codex uses `~/.codex/config.toml`, not the Claude JSON above; see
160https://www.contrie.com/docs/mcp#codex for its config and API-key alternative.
161These commands do not establish that a running conversation has reloaded its
162connection. On 2026-09-27 an existing Free account completed browser approval,
163account and verification checks, a live page read and unchanged request replay
164through Codex with no API key configured. Automatic token refresh and fresh
165signup were not exercised.
166
167After approval, call `contrie_account {}` (zero extraction credits), then try
168`contrie_read {"url":"https://example.com/","render":"never"}` for a live page
169read (1 credit on success). Tool discovery alone is not proof of account access.
170
171If a conversation still says Authentication required, reconnect/reload its MCP
172connection. In Claude Code: `/mcp` → contrie → Reconnect; Authenticate or
173Re-authenticate if offered. In Codex, use the login command above when needed,
174then reload the connection; if no reload action is available, restart the client
175and resume the conversation or start a new session. If refresh fails, sign in
176again. For claude.ai/Claude Desktop, reconnect in connector settings.
177
178To switch accounts, run `codex mcp logout contrie` or
179`claude mcp logout contrie`, choose the intended account in the next browser
180sign-in, then reconnect and check the account. A retained browser login may need
181sign-out first. When changing from a key to OAuth, remove the old credential
182source from this server's config; it can override the new sign-in. When changing
183to a helper-provided key, clear stored OAuth first. Do not delete an account or
184revoke unrelated keys. Clearing local credentials does not immediately revoke
185issued tokens everywhere. Full recovery: https://www.contrie.com/docs/mcp#connection-recovery.
186After authentication recovers, retain an interrupted extract/read's original
187inputs and idempotencyKey; do not silently replace the request identity.
188
189### API key — headless, CI and the REST API
190
191OAuth sign-in needs browser approval; API keys are the straightforward unattended
192CI/server alternative, and `/api/v1/*` is built for keys. Get one at https://www.contrie.com/dashboard/keys (human sign-up;
193skip this for the sample URLs below). Store it as an environment variable, never
194inline in a prompt or URL:
195
196```bash
197export CONTRIE_API_KEY=ck_live_...
198```
199
200Claude Code `.mcp.json`, as an alternative to the OAuth configuration above:
201
202```json
203{
204 "mcpServers": {
205 "contrie": {
206 "type": "http",
207 "url": "https://www.contrie.com/mcp",
208 "headers": { "Authorization": "Bearer ${CONTRIE_API_KEY}" }
209 }
210 }
211}
212```
213
214Tools exposed: `contrie_extract { url, extract?, schema?, maxAge?, render?, idempotencyKey? }` returns JSON.
215`contrie_read { url, maxAge?, render?, idempotencyKey? }` returns the full REST-shaped JSON response in an MCP
216text block (`data: null`, `markdown`, metadata/evidence; a successful read costs 1 credit and a failed one 0, and a successful rendered read adds 2).
217The REST-only options `format: "both"`, `options.timeout` and `options.waitFor` are not MCP tool arguments. `contrie_verify { data, url | html |
218text }` checks data you already have against its source page — no credits charged; with `html`, add `baseUrl` to resolve relative links.
219`contrie_watch` creates a monitor; `contrie_changes { id }` retrieves its changes; `contrie_monitors {}`
220lists your active monitors; `contrie_unwatch { id }` stops one. `contrie_account {}` reads your
221credits and restrictions. Listing, changes, stopping and the account check charge no
222credits. Eight tools are hosted.
223An operator-enabled pilot adds `contrie_check_fields` and `contrie_verification`
224only when the server lists them. Use the first with
225`{idempotencyKey: UUIDv4, source:{url,html}, contract:{version:1,fields}, proposedData?}`
226to check explicit entity/property/context relationships in HTML you already hold.
227It does not fetch its descriptive URL; `contrie_read` markdown is not original HTML.
228Keep the UUID and exact input for safe retry. It returns `{run,dashboardUrl}`;
229inspect `run.state` and `run.result.status`, `data`, and field decisions. A completed
230refusal with withheld data is a usable result, not an operational `isError`.
231`contrie_verification {executionId}` recovers; `{}` lists 25 runs and `{before:nextCursor}`
232continues history. Never combine ID and cursor. Shared workspace pilot limits apply;
233no extraction credits, including recovery at zero balance. Payloads last seven days,
234content-free retry identities 30 days. A source signature proves integrity, not
235authenticity, freshness or factual truth. Tools cannot write human labels. Use the
236same Contrie account to open `dashboardUrl`. Full example and bearer REST equivalent:
237https://www.contrie.com/docs/workspace#agent-workflow.
238Without any credential, clients can initialize and list tools, but only an exact recorded
239`contrie_extract` request below succeeds. Other tool calls, and invalid, expired
240or 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.
241
242### curl fallback (no MCP client available)
243
244This sample request needs no key and runs as printed, as a dry run before wiring up auth:
245
246```bash
247curl -X POST https://www.contrie.com/api/v1/scrape \
248 -H "Content-Type: application/json" \
249 -d '{"url": "https://example.com", "extract": "Extract the page title, heading, and all paragraph text"}'
250```
251
252For live work, change the request and add `-H "Authorization: Bearer $CONTRIE_API_KEY"`.
253A sample request sent with a key is live work and is charged like any other.
254
255Sample URLs work without a key, and each answers ONLY its recorded request —
256the exact prompt below, JSON format, no schema. Send anything else and it is a
257live extraction that needs authentication (the error says so):
258`https://news.ycombinator.com`, `https://example.com`,
259`https://github.com/trending`, `https://www.contrie.com/pricing`. Their recorded prompts:
260`"Get the top 5 stories with title, URL, and points"`,
261`"Extract the page title, heading, and all paragraph text"`,
262`"Get the top 5 trending repositories with name, description, language, and stars"`,
263`"Each plan with its monthly price in USD and included monthly credits"`.
264
265More recordings were asked with a JSON Schema and replay only when the request
266carries that exact schema as well as the exact prompt; `/llms.txt` lists the schemas.
267They are the dry run for schema mode, and their metadata includes `requestedFields`:
268`https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html` with `"The product name and its current price"`, and
269`https://quotes.toscrape.com/` with `"Only the first 3 quotes on the page"`, and
270`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"`,
271`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"`,
272`https://arxiv.org/abs/1602.03837` with `"The citation details of this paper: title, authors, submission date, journal reference, DOI and primary subject"`,
273`https://pypi.org/project/requests/` with `"The package name, latest version, release date, license, required Python version and one-line summary"`,
274`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"`,
275`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"`.
276
277## Decision procedure
278
2791. **Reading vs. structuring.** If the goal is to read or summarize a page,
280 use `format: "markdown"` — readable output costs 1 credit
281 before any rendering surcharge and has `qualityScoreKind: "not_applicable"`. If downstream code depends on a specific shape, use `schema`
282 instead of `extract`, declare mandatory fields in `required`, and check `success`
283 before consuming the answer. For structured output, `success: true` already means
284 `metadata.valid` is true and the quality score is at least 70; the other fields explain a
285 refusal and scope an accepted answer, they are not a second gate. Rejected candidates are not usable output.
2862. **Natural language vs. schema.** Prefer `extract` (a plain-English
287 description) for exploratory or one-off pulls. Prefer `schema` (JSON
288 Schema: `object`/`array`/`string`/`number`/`integer`/`boolean`,
289 `properties`, `required`, `items`, `enum`, `description`) whenever the
290 caller parses the result programmatically. Unsupported keywords are carried
291 unchecked; a local `$ref` is inlined and a nullable `anyOf` becomes a type list.
292 Only unusable schemas are refused, with a 400 naming the keyword. Unknown fields
293 in a scrape or extract body are refused with a 400 that names them.
2943. **Checking the result.** Check `success` first. For structured output, inspect
295 `metadata.valid`, `metadata.schemaValid` (when a schema was supplied), and requested-field coverage. Success requires local validation, a score of
296 at least 70, all declared schema properties returned in each applicable
297 object and array item, including optional properties, and at least half of all
298 returned values found in the page text. `metadata.requestedFields`
299 reports total/returned leaf counts and up to 50 missing paths. Use nullable
300 types for values that may be unavailable: explicit `null` acknowledges the field
301 but lowers `metadata.completeness`, the populated fraction. Extra fields cannot
302 compensate for omissions. These checks do not establish semantic correctness,
303 the number of matching source items, or completeness against a natural-language
304 request. Requested-field coverage is absent when no declared shape is measured.
305 - A high score alone does not establish that validation passed. After checking
306 success/validity, use grounding coverage to inspect text support and verify field meaning.
307 - Low score: inspect missing fields and source availability before changing the
308 request. The score alone does not diagnose the cause; a new call can cost resources.
309 - Refused (`success: false`, `RESULT_NOT_ACCEPTED`): a refusal carries no `groundingFields`
310 or values. Read `metadata.requestedFields.missing` and `metadata.groundingCoverage` (at
311 least half of returned values must be found), then retry once with nullable fields, values
312 asked for as the page writes them, or fewer fields.
313 - Low grounding on an accepted answer (`success: true`): read
314 `groundingFields` and treat each `grounded: false` entry as UNCONFIRMED,
315 not as wrong: the value may be absent, or it may be presented differently
316 in the page than in the result. Inspect those `path`s first, and retry
317 with a narrower `extract` only where inspection suggests a real miss. The
318 `excerpt` on each grounded entry is the audit trail for a human check.
319 - Binding conflicts: an accepted model answer from a current deployment
320 carries `metadata.binding` (`judged`, `conflicts: [{ path }]`, `truncated`);
321 recordings and responses stored before 2026-09-28 lack it, and absence
322 means no check ran. Each conflict `path` is a field whose value is on the
323 page, but the passages about that field state a different value. Treat those
324 fields as UNCONFIRMED and inspect them before use; the rest of the answer
325 stands. It is not a truth claim and changes neither acceptance nor credits.
326 `judged: 0` means no field could be checked, not that all passed;
327 `truncated: true` means some values were not judged.
3284. **RENDER_REQUIRED.** Inspect whether rendering was disabled, unavailable or
329 attempted. An eligible request may use auto/always rendering or supplied HTML;
330 do not loop unchanged or assume a login wall is supported.
3315. **Credits.** `metadata.credits` reports this extraction's customer consumption.
332 Rejected structured results cost 0; accepted structured output costs 1, 3, 8 or 15
333 credits before a successful rendering surcharge. Charges and source support
334 depend on the request and available account capacity.
3356. **Data from somewhere else.** To check data you did not get from Contrie —
336 another extractor's output, your own scrape, a stored record — send it to
337 `POST /api/v1/verify` (or the `contrie_verify` tool) with the page. It runs
338 the same grounding check. For the same data/source bytes it is deterministic and
339 charges no credits. Contrie's own signed extractions carry text-support
340 evidence inline, but you still need to inspect attribution, freshness and
341 factual meaning for consequential use.
342
343## Request and result example
344
345This is an excerpt of the recorded answer the keyless sample replays, not a complete
346signed packet. Exact recorded calls return historical provenance and zero current
347credits. With no schema the requested fields are not counted (`coverageMeasured: false`),
348so the score is at most 80.
349
350```json
351{ "url": "https://example.com", "extract": "Extract the page title, heading, and all paragraph text" }
352```
353
354```json
355{
356 "success": true,
357 "data": { "title": "Example Domain", "heading": "Example Domain" },
358 "metadata": {
359 "qualityScore": 80,
360 "valid": true,
361 "coverageMeasured": false,
362 "grounding": 1,
363 "credits": 0,
364 "source": { "mode": "recording" },
365 "trace": [{ "stage": "complete", "detail": "Request complete" }]
366 }
367}
368```
369
370## Streaming and recovery
371
372Set `Accept: application/x-ndjson` on a live extraction to receive progress then a
373terminal result or error. The compatibility event name is `trace`; the only public
374stages are `loading`, `processing` and `complete`, with fixed display labels.
375Check the final `success`, not the HTTP 200 of an already-open stream. Handle
376chunk boundaries, a final line without a newline, cancellation and premature
377connection closure. A progress event contains no partial answer.
378
379On authenticated non-streaming JSON calls, `Idempotency-Key` binds the account,
380operation and inputs. Use 8–200 visible ASCII characters. An identical request can
381replay its retained response for 24 hours without new extraction work. HTTP 409
382covers in-progress, changed-input, expired or unknown outcomes. Do not silently
383use a new key after an unknown outcome: it deliberately authorizes new work.
384Hosted `contrie_extract`
385and `contrie_read` accept an optional `idempotencyKey` argument with the same
38624-hour recovery behavior. Save the original arguments and reuse them unchanged
387after an interrupted response. Recovery returns the retained response. A signed
388response whose fields are all still public comes back unchanged, original signature
389included; otherwise it comes back narrowed to the current public contract and
390unsigned (`evidenceStatus: "unavailable"`, or `"not_issued_for_rejected_result"` for a rejected answer). Either way it keeps the original source
391time and charge, and it does not refresh the page or charge again. Check the MCP
392`isError` flag and embedded decision even on replay. Refresh your client's tool
393inventory after an update. Streaming and monitor creation do not support this
394caller retry identity. Calls without it remain separate work.
395
396Recordings are anonymous, exact sample requests. Presenting authentication or
397explicit acquisition options requests live work instead; never count a recorded
398response as an external live extraction.
399
400## Limits and errors
401
402The Free allowance is 200 credits a month and 10 requests/minute per account (across all of its keys).
403All plans: Free 200, Builder 10,000, Pro 40,000 credits a month; Free 10, Builder 30, Pro 100 requests per minute.
404Each plan caps one request's credits, rendering included: Free 3, Builder 5, Pro 17. An answer above
405the cap, or above the account's remaining credits, is refused as 429 `INFERENCE_BUDGET_EXCEEDED` at
4060 credits, and the message says so; ask for fewer or simpler fields, or render "never".
407Available service capacity is also required. Quota alone does not guarantee an answer.
408Free service capacity is funded again each calendar month (UTC) from a shared monthly pool.
409A month whose pool is already spent grants nothing further until the next one, so the next
410month is a likely but not a guaranteed remedy. Check account status once when connecting or
411after a capacity refusal; do not poll it, and do not assume a new key removes that refusal.
412Source HTML/text is limited to 5,000,000 UTF-8 bytes; serialized schemas to 10,000
413UTF-8 bytes; `extract` to 4,000 characters. The hosting platform can reject a combined body sooner.
414Contrie reads at most the first 100,000 characters of a page's markdown, for extraction and
415markdown alike; `metadata.evidenceCoverage.sourceTruncated` is true when it cut.
416
417Monthly prices (USD): Free $0, Builder $19, Pro $79. On an active paid subscription, overage is
418on by default at $2 per 1,000 credits, up to a monthly spending limit of $20 unless raised;
419requests stop at that limit. Free has no overage. See https://www.contrie.com/pricing.
420
421Errors have `{success:false,error:{code,message}}`. Read the status, code and
422`Retry-After` when present. Over MCP there are no headers: an origin rate limit arrives as `SOURCE_REFUSED`
423with no wait (by design, the wait is a REST header or nothing), so use a bounded backoff, for example
42430 s then 2 min, before one or two retries. 400 means invalid input; 401/403 means authentication
425or permission; 422 covers an unsupported or inaccessible source; 429 means a
426request or account limit; 503 means temporarily unavailable service. A refused
427structured answer is not a result to consume. Avoid repeated unchanged retries: a
428`FETCH_FAILED` caused by a missing page (404 or 410), a page over 10 MB or more than 10
429redirects fails the same way every time, so check the URL instead.
430
431## References
432
433- https://www.contrie.com/docs/scrape
434- https://www.contrie.com/docs/extract
435- https://www.contrie.com/docs/streaming
436- https://www.contrie.com/docs/evidence
437- https://www.contrie.com/docs/verify
438- https://www.contrie.com/docs/rate-limits
439- https://www.contrie.com/docs/errors
440- https://www.contrie.com/openapi.json
441
442## Before starting or repeating live work
443
444Call `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.
445
446## First live job: one product name and price
447
448Use 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`.
449
450<!-- product-job-example:start -->
451```json
452{
453 "url": "https://your-store.example/product",
454 "schema": {
455 "type": "object",
456 "properties": {
457 "name": {
458 "type": "string"
459 },
460 "offers": {
461 "type": "object",
462 "properties": {
463 "price": {
464 "type": "number"
465 },
466 "priceCurrency": {
467 "type": "string"
468 }
469 },
470 "required": [
471 "price",
472 "priceCurrency"
473 ],
474 "additionalProperties": false
475 }
476 },
477 "required": [
478 "name",
479 "offers"
480 ],
481 "additionalProperties": false
482 },
483 "options": {
484 "maxAge": 0
485 }
486}
487```
488<!-- product-job-example:end -->
489
490Require `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.