Recipes
A recipe is one job: the request that does it, the response a production run returned, and what to check before you use the answer.
The 10 recorded recipes run right now without an API key. Send the request exactly as printed and Contrie replays the recorded run: no fresh fetch, 0 credits. Change the URL, the prompt or the schema and it becomes a live request, which needs a key.
Recipe 01
Rank a list and keep its order
Use it for a leaderboard, a trending page or search results: anywhere position carries meaning. Asking for page order and declaring rank in the schema keeps that order explicit in the data instead of implied by the array. Each row prints three numbers and labels only the weekly one, so the schema names all three: forks gives the unlabelled second number a field of its own.
curl -X POST https://www.contrie.com/api/v1/scrape \
-H "Content-Type: application/json" \
-d '{
"url": "https://github.com/trending/rust?since=weekly",
"extract": "The top 10 trending repositories this week, in page order, with total stars, forks and stars gained this week",
"schema": {
"type": "object",
"required": ["repositories"],
"properties": {
"repositories": {
"type": "array",
"items": {
"type": "object",
"required": [
"rank",
"repository",
"description",
"language",
"stars",
"forks",
"stars_this_week"
],
"properties": {
"rank": { "type": "integer" },
"repository": { "type": "string" },
"description": { "type": ["string", "null"] },
"language": { "type": ["string", "null"] },
"stars": { "type": "integer" },
"forks": { "type": "integer" },
"stars_this_week": { "type": "integer" }
}
}
}
}
}
}'{
"name": "contrie_extract",
"arguments": {
"url": "https://github.com/trending/rust?since=weekly",
"extract": "The top 10 trending repositories this week, in page order, with total stars, forks and stars gained this week",
"schema": {
"type": "object",
"required": ["repositories"],
"properties": {
"repositories": {
"type": "array",
"items": {
"type": "object",
"required": [
"rank",
"repository",
"description",
"language",
"stars",
"forks",
"stars_this_week"
],
"properties": {
"rank": { "type": "integer" },
"repository": { "type": "string" },
"description": { "type": ["string", "null"] },
"language": { "type": ["string", "null"] },
"stars": { "type": "integer" },
"forks": { "type": "integer" },
"stars_this_week": { "type": "integer" }
}
}
}
}
}
}
}acceptedquality 9470/70 fields60/70 in the page text1 credit
{
"success": true,
"data": {
"repositories": [
{
"rank": 1,
"repository": "akitaonrails/ai-memory",
"description": "Solution for long term memory for agent coding CLIs and to facilitate handoff between different agent vendors",
"language": "Rust",
"stars": 8569,
"forks": 581,
"stars_this_week": 1110
},
{
"rank": 2,
"repository": "cloudflare/quiche",
"description": "🥧 Savoury implementation of the QUIC transport protocol and HTTP/3",
"language": "Rust",
"stars": 12690,
"forks": 1153,
"stars_this_week": 522
},
{
"rank": 3,
"repository": "hydra-db/hydradb",
"description": "HydraDB - fast graph database on object storage",
"language": "Rust",
"stars": 12287,
"forks": 5394,
"stars_this_week": 8467
}
]
},
"metadata": {
"valid": true,
"schemaValid": true,
"qualityScore": 94,
"requestedFields": { "total": 70, "returned": 70, "missing": [] },
"groundingCoverage": { "total": 70, "checkable": 70, "grounded": 60 },
"credits": 1
}
}A real production response, trimmed for the page: data shows the first 3 of 10 items, and metadata shows the fields to branch on. The full response also carries groundingFields, source and trace. Run it yourself and the replay reports credits: 0 and source.mode: "recording".
Recipe 02
Read a ranked table and keep each value with its row
Use it for reference tables that carry several numbers per row. Declaring the row as an object keeps a height, a floor count and a year attached to the building they describe.
curl -X POST https://www.contrie.com/api/v1/scrape \
-H "Content-Type: application/json" \
-d '{
"url": "https://en.wikipedia.org/wiki/List_of_tallest_buildings",
"extract": "The five tallest buildings in rank order, with city, country, height in metres, floors and year completed",
"schema": {
"type": "object",
"required": ["buildings"],
"properties": {
"buildings": {
"type": "array",
"items": {
"type": "object",
"required": ["rank", "name", "city", "country", "height_m", "floors", "year"],
"properties": {
"rank": { "type": "integer" },
"name": { "type": "string" },
"city": { "type": "string" },
"country": { "type": "string" },
"height_m": { "type": "number" },
"floors": { "type": "integer" },
"year": { "type": "integer" }
}
}
}
}
}
}'{
"name": "contrie_extract",
"arguments": {
"url": "https://en.wikipedia.org/wiki/List_of_tallest_buildings",
"extract": "The five tallest buildings in rank order, with city, country, height in metres, floors and year completed",
"schema": {
"type": "object",
"required": ["buildings"],
"properties": {
"buildings": {
"type": "array",
"items": {
"type": "object",
"required": ["rank", "name", "city", "country", "height_m", "floors", "year"],
"properties": {
"rank": { "type": "integer" },
"name": { "type": "string" },
"city": { "type": "string" },
"country": { "type": "string" },
"height_m": { "type": "number" },
"floors": { "type": "integer" },
"year": { "type": "integer" }
}
}
}
}
}
}
}acceptedquality 10035/35 fields35/35 in the page text1 credit
{
"success": true,
"data": {
"buildings": [
{
"rank": 1,
"name": "Burj Khalifa",
"city": "Dubai",
"country": "United Arab Emirates",
"height_m": 828,
"floors": 163,
"year": 2010
},
{
"rank": 2,
"name": "Merdeka Maybank Tower",
"city": "Kuala Lumpur",
"country": "Malaysia",
"height_m": 678.9,
"floors": 118,
"year": 2024
},
{
"rank": 3,
"name": "Shanghai Tower",
"city": "Shanghai",
"country": "China",
"height_m": 632,
"floors": 128,
"year": 2015
}
]
},
"metadata": {
"valid": true,
"schemaValid": true,
"qualityScore": 100,
"requestedFields": { "total": 35, "returned": 35, "missing": [] },
"groundingCoverage": { "total": 35, "checkable": 35, "grounded": 35 },
"credits": 1
}
}A real production response, trimmed for the page: data shows the first 3 of 5 items, and metadata shows the fields to branch on. The full response also carries groundingFields, source and trace. Run it yourself and the replay reports credits: 0 and source.mode: "recording".
Recipe 03
Cite a paper
Use it to build a reference list, or to check a citation an agent wrote. journal_reference and doi are nullable in the schema, so a preprint can say it has neither. The doi that came back is the one arXiv issued, 10.48550/arXiv.1602.03837; the journal's own DOI is on the page as the "Related DOI", so ask for that one by name when you need the publisher's.
curl -X POST https://www.contrie.com/api/v1/scrape \
-H "Content-Type: application/json" \
-d '{
"url": "https://arxiv.org/abs/1602.03837",
"extract": "The citation details of this paper: title, authors, submission date, journal reference, DOI and primary subject",
"schema": {
"type": "object",
"required": [
"title",
"authors",
"submitted",
"journal_reference",
"doi",
"primary_subject"
],
"properties": {
"title": { "type": "string" },
"authors": { "type": "array", "items": { "type": "string" } },
"submitted": { "type": "string" },
"journal_reference": { "type": ["string", "null"] },
"doi": { "type": ["string", "null"] },
"primary_subject": { "type": "string" }
}
}
}'{
"name": "contrie_extract",
"arguments": {
"url": "https://arxiv.org/abs/1602.03837",
"extract": "The citation details of this paper: title, authors, submission date, journal reference, DOI and primary subject",
"schema": {
"type": "object",
"required": [
"title",
"authors",
"submitted",
"journal_reference",
"doi",
"primary_subject"
],
"properties": {
"title": { "type": "string" },
"authors": { "type": "array", "items": { "type": "string" } },
"submitted": { "type": "string" },
"journal_reference": { "type": ["string", "null"] },
"doi": { "type": ["string", "null"] },
"primary_subject": { "type": "string" }
}
}
}
}acceptedquality 1007/7 fields7/7 in the page text1 credit
{
"success": true,
"data": {
"title": "Observation of Gravitational Waves from a Binary Black Hole Merger",
"authors": ["The LIGO Scientific Collaboration", "the Virgo Collaboration"],
"submitted": "11 Feb 2016",
"journal_reference": "Phys. Rev. Lett. 116, 061102 (2016)",
"doi": "10.48550/arXiv.1602.03837",
"primary_subject": "General Relativity and Quantum Cosmology (gr-qc)"
},
"metadata": {
"valid": true,
"schemaValid": true,
"qualityScore": 100,
"requestedFields": { "total": 7, "returned": 7, "missing": [] },
"groundingCoverage": { "total": 7, "checkable": 7, "grounded": 7 },
"credits": 1
}
}A real production response, trimmed for the page: metadata shows the fields to branch on. The full response also carries groundingFields, source and trace. Run it yourself and the replay reports credits: 0 and source.mode: "recording".
Recipe 04
Enrich a lead from a company page
Use it to fill a CRM record or brief a sales agent from a page you already trust. Arrays in the schema keep several industries or founders as separate values instead of one joined string, so each can be checked against the page on its own.
curl -X POST https://www.contrie.com/api/v1/scrape \
-H "Content-Type: application/json" \
-d '{
"url": "https://en.wikipedia.org/wiki/Stripe,_Inc.",
"extract": "The company profile from the infobox: name, industries, year founded, founders, headquarters, revenue and number of employees",
"schema": {
"type": "object",
"required": [
"name",
"industries",
"founded",
"founders",
"headquarters",
"revenue",
"employees"
],
"properties": {
"name": { "type": "string" },
"industries": { "type": "array", "items": { "type": "string" } },
"founded": { "type": "integer" },
"founders": { "type": "array", "items": { "type": "string" } },
"headquarters": { "type": "string" },
"revenue": { "type": ["string", "null"] },
"employees": { "type": ["integer", "null"] }
}
}
}'{
"name": "contrie_extract",
"arguments": {
"url": "https://en.wikipedia.org/wiki/Stripe,_Inc.",
"extract": "The company profile from the infobox: name, industries, year founded, founders, headquarters, revenue and number of employees",
"schema": {
"type": "object",
"required": [
"name",
"industries",
"founded",
"founders",
"headquarters",
"revenue",
"employees"
],
"properties": {
"name": { "type": "string" },
"industries": { "type": "array", "items": { "type": "string" } },
"founded": { "type": "integer" },
"founders": { "type": "array", "items": { "type": "string" } },
"headquarters": { "type": "string" },
"revenue": { "type": ["string", "null"] },
"employees": { "type": ["integer", "null"] }
}
}
}
}acceptedquality 1009/9 fields9/9 in the page text1 credit
{
"success": true,
"data": {
"name": "Stripe, Inc.",
"industries": ["Financial services", "Payment processor"],
"founded": 2009,
"founders": ["Patrick Collison", "John Collison"],
"headquarters": "South San Francisco, California, U.S. and Dublin, Ireland",
"revenue": "US$5.1 billion",
"employees": 8500
},
"metadata": {
"valid": true,
"schemaValid": true,
"qualityScore": 100,
"requestedFields": { "total": 9, "returned": 9, "missing": [] },
"groundingCoverage": { "total": 9, "checkable": 9, "grounded": 9 },
"credits": 1
}
}A real production response, trimmed for the page: metadata shows the fields to branch on. The full response also carries groundingFields, source and trace. Run it yourself and the replay reports credits: 0 and source.mode: "recording".
Recipe 05
Read official exchange rates
Use it when a number has to be the published one: rates, tariffs, fee tables. Declaring rate as a number and asking for the date keeps a stale table from passing as today's.
curl -X POST https://www.contrie.com/api/v1/scrape \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html",
"extract": "Every euro foreign exchange reference rate on the page, with the date they apply to",
"schema": {
"type": "object",
"required": ["date", "rates"],
"properties": {
"date": { "type": "string" },
"rates": {
"type": "array",
"items": {
"type": "object",
"required": ["code", "currency", "rate"],
"properties": {
"code": { "type": "string" },
"currency": { "type": "string" },
"rate": { "type": "number" }
}
}
}
}
}
}'{
"name": "contrie_extract",
"arguments": {
"url": "https://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html",
"extract": "Every euro foreign exchange reference rate on the page, with the date they apply to",
"schema": {
"type": "object",
"required": ["date", "rates"],
"properties": {
"date": { "type": "string" },
"rates": {
"type": "array",
"items": {
"type": "object",
"required": ["code", "currency", "rate"],
"properties": {
"code": { "type": "string" },
"currency": { "type": "string" },
"rate": { "type": "number" }
}
}
}
}
}
}
}acceptedquality 10088/88 fields88/88 in the page text1 credit
{
"success": true,
"data": {
"date": "18 September 2026",
"rates": [
{ "code": "USD", "currency": "US dollar", "rate": 1.146 },
{ "code": "JPY", "currency": "Japanese yen", "rate": 180.94 },
{ "code": "CZK", "currency": "Czech koruna", "rate": 24.339 }
]
},
"metadata": {
"valid": true,
"schemaValid": true,
"qualityScore": 100,
"requestedFields": { "total": 88, "returned": 88, "missing": [] },
"groundingCoverage": { "total": 88, "checkable": 88, "grounded": 88 },
"credits": 1
}
}A real production response, trimmed for the page: data shows the first 3 of 29 items, and metadata shows the fields to branch on. The full response also carries groundingFields, source and trace. Run it yourself and the replay reports credits: 0 and source.mode: "recording".
Recipe 06
Check a package before upgrading
Use it before an agent bumps a dependency: the latest version, its release date, its license and the Python it needs, read from the package's own page.
curl -X POST https://www.contrie.com/api/v1/scrape \
-H "Content-Type: application/json" \
-d '{
"url": "https://pypi.org/project/requests/",
"extract": "The package name, latest version, release date, license, required Python version and one-line summary",
"schema": {
"type": "object",
"required": ["name", "version", "released", "license", "requires_python", "summary"],
"properties": {
"name": { "type": "string" },
"version": { "type": "string" },
"released": { "type": "string" },
"license": { "type": ["string", "null"] },
"requires_python": { "type": ["string", "null"] },
"summary": { "type": "string" }
}
}
}'{
"name": "contrie_extract",
"arguments": {
"url": "https://pypi.org/project/requests/",
"extract": "The package name, latest version, release date, license, required Python version and one-line summary",
"schema": {
"type": "object",
"required": ["name", "version", "released", "license", "requires_python", "summary"],
"properties": {
"name": { "type": "string" },
"version": { "type": "string" },
"released": { "type": "string" },
"license": { "type": ["string", "null"] },
"requires_python": { "type": ["string", "null"] },
"summary": { "type": "string" }
}
}
}
}acceptedquality 1006/6 fields6/6 in the page text1 credit
{
"success": true,
"data": {
"name": "requests",
"version": "2.34.2",
"released": "May 14, 2026",
"license": "Apache Software License (Apache-2.0)",
"requires_python": ">=3.10",
"summary": "Python HTTP for Humans."
},
"metadata": {
"valid": true,
"schemaValid": true,
"qualityScore": 100,
"requestedFields": { "total": 6, "returned": 6, "missing": [] },
"groundingCoverage": { "total": 6, "checkable": 6, "grounded": 6 },
"credits": 1
}
}A real production response, trimmed for the page: metadata shows the fields to branch on. The full response also carries groundingFields, source and trace. Run it yourself and the replay reports credits: 0 and source.mode: "recording".
Recipe 07
Track a price and its currency
Use it for price checks, where a wrong number costs more than a missing one. The schema asks for a price and a currency, the shape most product feeds expect.
curl -X POST https://www.contrie.com/api/v1/scrape \
-H "Content-Type: application/json" \
-d '{
"url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"extract": "The product name and its current price",
"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
}
}'{
"name": "contrie_extract",
"arguments": {
"url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"extract": "The product name and its current price",
"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
}
}
}acceptedquality 1003/3 fields3/3 in the page text1 credit
{
"success": true,
"data": {
"name": "A Light in the Attic",
"offers": { "price": 51.77, "priceCurrency": "GBP" }
},
"metadata": {
"valid": true,
"schemaValid": true,
"qualityScore": 100,
"requestedFields": { "total": 3, "returned": 3, "missing": [] },
"groundingCoverage": { "total": 3, "checkable": 3, "grounded": 3 },
"credits": 1
}
}A real production response, trimmed for the page: metadata shows the fields to branch on. The full response also carries groundingFields, source and trace. Run it yourself and the replay reports credits: 0 and source.mode: "recording".
Recipe 08
Read every plan off a pricing page
Use it to compare vendors or keep a cost model current. The request is plain language with no schema, which suits an answer a person or a model will read; pass a schema when code depends on the shape.
curl -X POST https://www.contrie.com/api/v1/scrape \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.contrie.com/pricing",
"extract": "Each plan with its monthly price in USD and included monthly credits"
}'{
"name": "contrie_extract",
"arguments": {
"url": "https://www.contrie.com/pricing",
"extract": "Each plan with its monthly price in USD and included monthly credits"
}
}acceptedquality 809/9 in the page text1 credit
{
"success": true,
"data": [
{ "plan_name": "Free", "monthly_price_usd": 0, "monthly_credits": 200 },
{ "plan_name": "Builder", "monthly_price_usd": 19, "monthly_credits": 10000 },
{ "plan_name": "Pro", "monthly_price_usd": 79, "monthly_credits": 40000 }
],
"metadata": {
"valid": true,
"qualityScore": 80,
"groundingCoverage": { "total": 9, "checkable": 9, "grounded": 9 },
"credits": 1
}
}A real production response, trimmed for the page: metadata shows the fields to branch on. The full response also carries groundingFields, source and trace. Run it yourself and the replay reports credits: 0 and source.mode: "recording".
Recipe 09
Keep quotes with their authors
Use it for quotations, reviews or testimonials, where the words and the person who said them must stay together. One object per quote keeps text, author and tags in the same place.
curl -X POST https://www.contrie.com/api/v1/scrape \
-H "Content-Type: application/json" \
-d '{
"url": "https://quotes.toscrape.com/",
"extract": "Only the first 3 quotes on the page",
"schema": {
"type": "object",
"properties": {
"quotes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"text": { "type": "string" },
"author": { "type": "string" },
"tags": { "type": "array", "items": { "type": "string" } }
},
"required": ["text", "author", "tags"],
"additionalProperties": false
}
}
},
"required": ["quotes"],
"additionalProperties": false
}
}'{
"name": "contrie_extract",
"arguments": {
"url": "https://quotes.toscrape.com/",
"extract": "Only the first 3 quotes on the page",
"schema": {
"type": "object",
"properties": {
"quotes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"text": { "type": "string" },
"author": { "type": "string" },
"tags": { "type": "array", "items": { "type": "string" } }
},
"required": ["text", "author", "tags"],
"additionalProperties": false
}
}
},
"required": ["quotes"],
"additionalProperties": false
}
}
}acceptedquality 10017/17 fields17/17 in the page text1 credit
{
"success": true,
"data": {
"quotes": [
{
"text": "The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.",
"author": "Albert Einstein",
"tags": ["change", "deep-thoughts", "thinking", "world"]
},
{
"text": "It is our choices, Harry, that show what we truly are, far more than our abilities.",
"author": "J.K. Rowling",
"tags": ["abilities", "choices"]
},
{
"text": "There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.",
"author": "Albert Einstein",
"tags": ["inspirational", "life", "live", "miracle", "miracles"]
}
]
},
"metadata": {
"valid": true,
"schemaValid": true,
"qualityScore": 100,
"requestedFields": { "total": 17, "returned": 17, "missing": [] },
"groundingCoverage": { "total": 17, "checkable": 17, "grounded": 17 },
"credits": 1
}
}A real production response, trimmed for the page: metadata shows the fields to branch on. The full response also carries groundingFields, source and trace. Run it yourself and the replay reports credits: 0 and source.mode: "recording".
Recipe 10
Read a simple page
Use it to check your client, your parsing and your branching before you point them at a page that matters.
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"
}'{
"name": "contrie_extract",
"arguments": {
"url": "https://example.com",
"extract": "Extract the page title, heading, and all paragraph text"
}
}acceptedquality 804/4 in the page text1 credit
{
"success": true,
"data": {
"title": "Example Domain",
"heading": "Example Domain",
"paragraphs": [
"This domain is for use in documentation examples without needing permission. Avoid use in operations.",
"Learn more"
]
},
"metadata": {
"valid": true,
"qualityScore": 80,
"groundingCoverage": { "total": 4, "checkable": 4, "grounded": 4 },
"credits": 1
}
}A real production response, trimmed for the page: metadata shows the fields to branch on. The full response also carries groundingFields, source and trace. Run it yourself and the replay reports credits: 0 and source.mode: "recording".
Recipe 11
Read a page as markdown
format: "markdown" skips extraction entirely: 1 credit, and data is null. Its qualityScoreKind is not_applicable; the numeric placeholder 0 is not a quality grade.
curl -X POST https://www.contrie.com/api/v1/scrape \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $CONTRIE_API_KEY" \
-d '{ "url": "https://news.ycombinator.com", "format": "markdown" }'{ "name": "contrie_read", "arguments": { "url": "https://news.ycombinator.com" } }No response is printed here: this page shows only responses recorded from production, and this call has no recording. Scrape reference
Recipe 12
Verify a record you already have
Use it on data from another extractor, your own scrape or a stored record; here it is the record from the price recipe above. Verify answers one question: is this value present in this page. It bounds invention, not correctness. Verify currently charges no customer credits; only the per-account rate limit applies.
curl -X POST https://www.contrie.com/api/v1/verify \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $CONTRIE_API_KEY" \
-d '{
"url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"data": {
"name": "A Light in the Attic",
"offers": { "price": 51.77, "priceCurrency": "GBP" }
}
}'{
"name": "contrie_verify",
"arguments": {
"url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"data": {
"name": "A Light in the Attic",
"offers": { "price": 51.77, "priceCurrency": "GBP" }
}
}
}No response is printed here: this page shows only responses recorded from production, and this call has no recording. Verify reference
Recipe 13
Watch a page for changes
A monitor is a standing question about one page: here, the price recipe's question asked every 60 minutes. Contrie answers it now, answers it again on a schedule, and records a change event when the answer moves. Each run costs what one extraction costs; an unchanged page writes no event. It keeps running, and charging, until you stop it with contrie_unwatch or DELETE /api/v1/monitors/:id.
curl -X POST https://www.contrie.com/api/v1/monitors \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $CONTRIE_API_KEY" \
-d '{
"url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"extract": "The product name and its current price",
"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
},
"every": 60,
"webhookUrl": "https://hooks.example.com/contrie"
}'{
"name": "contrie_watch",
"arguments": {
"url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"extract": "The product name and its current price",
"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
},
"every": 60,
"webhookUrl": "https://hooks.example.com/contrie"
}
}No response is printed here: this page shows only responses recorded from production, and this call has no recording. Monitors reference
Recipe 14
Read what changed
When a watched answer changes, the monitor records the before and after (each signed when its answer was accepted) with a diff of the fields that moved. Read the events by monitor id; the same change is sent to your webhook.
curl https://www.contrie.com/api/v1/monitors/$MONITOR_ID \ -H "Authorization: Bearer $CONTRIE_API_KEY"
{
"name": "contrie_changes",
"arguments": { "id": "<the id contrie_watch returned>" }
}No response is printed here: this page shows only responses recorded from production, and this call has no recording. Monitors reference
Recipe 15
Branching on the response
A 200 status doesn't mean the data is good, and a caught error doesn't always mean give up. This is roughly what a production caller should do:
async function extract(url, prompt) {
const res = await fetch("https://www.contrie.com/api/v1/scrape", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.CONTRIE_API_KEY}`,
},
body: JSON.stringify({ url, extract: prompt }),
});
const body = await res.json();
if (!res.ok || !body.success) {
// Refused results are not usable data. Inspect the code and Retry-After.
return { accepted: false, error: body.error };
}
if (body.metadata?.qualityScoreKind !== "not_applicable") {
// Apply your workload's acceptance criteria and inspect source evidence.
const support = body.metadata?.grounding;
if (support === undefined || support < 0.8) {
return { accepted: false, needsReview: true };
}
}
return body;
}