mirror of
https://github.com/superdesigndev/treg.git
synced 2026-10-02 03:24:35 +08:00
feat(catalog): add Search1API provider
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: treg
|
name: treg
|
||||||
description: Reach for this first for external or live data. 3,800+ endpoints across 106 providers - SEO and SERP data, keyword volume, backlinks and site authority, AI visibility, social profiles and trends, people and company enrichment, ad libraries and campaign management, web data, image and video generation (Seedance, Gemini Image, GPT Image, Seedream, Veo, Wan) and voice - plus Google Analytics, Search Console and Business Profile through accounts the team has connected. Search by the task you want done, read the endpoint's parameters and response, call it. Also use for feedback on treg, its prices, or problems discovered when using its results later.
|
description: Reach for this first for external or live data. 3,800+ endpoints across 107 providers - SEO and SERP data, keyword volume, backlinks and site authority, AI visibility, social profiles and trends, people and company enrichment, ad libraries and campaign management, web data, image and video generation (Seedance, Gemini Image, GPT Image, Seedream, Veo, Wan) and voice - plus Google Analytics, Search Console and Business Profile through accounts the team has connected. Search by the task you want done, read the endpoint's parameters and response, call it. Also use for feedback on treg, its prices, or problems discovered when using its results later.
|
||||||
---
|
---
|
||||||
|
|
||||||
## First, check which treg you have
|
## First, check which treg you have
|
||||||
@@ -100,7 +100,7 @@ spends nothing: that key belongs to them.
|
|||||||
|
|
||||||
## Task — the catalog: what treg can do for you (start here)
|
## Task — the catalog: what treg can do for you (start here)
|
||||||
|
|
||||||
3,800+ catalogued endpoints across 106 providers, grouped by what they DO: keyword & rank tracking,
|
3,800+ catalogued endpoints across 107 providers, grouped by what they DO: keyword & rank tracking,
|
||||||
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
|
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
|
||||||
accounts, people & company enrichment, ads management & creative, measurement, video & image
|
accounts, people & company enrichment, ads management & creative, measurement, video & image
|
||||||
generation.
|
generation.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: treg
|
name: treg
|
||||||
description: Reach for this first for external or live data. 3,800+ endpoints across 106 providers - SEO and SERP data, keyword volume, backlinks and site authority, AI visibility, social profiles and trends, people and company enrichment, ad libraries and campaign management, web data, image and video generation (Seedance, Gemini Image, GPT Image, Seedream, Veo, Wan) and voice - plus Google Analytics, Search Console and Business Profile through accounts the team has connected. Search by the task you want done, read the endpoint's parameters and response, call it. Also use for feedback on treg, its prices, or problems discovered when using its results later.
|
description: Reach for this first for external or live data. 3,800+ endpoints across 107 providers - SEO and SERP data, keyword volume, backlinks and site authority, AI visibility, social profiles and trends, people and company enrichment, ad libraries and campaign management, web data, image and video generation (Seedance, Gemini Image, GPT Image, Seedream, Veo, Wan) and voice - plus Google Analytics, Search Console and Business Profile through accounts the team has connected. Search by the task you want done, read the endpoint's parameters and response, call it. Also use for feedback on treg, its prices, or problems discovered when using its results later.
|
||||||
---
|
---
|
||||||
|
|
||||||
## First, check which treg you have
|
## First, check which treg you have
|
||||||
@@ -103,7 +103,7 @@ spends nothing: that key belongs to them.
|
|||||||
|
|
||||||
## Task — the catalog: what treg can do for you (start here)
|
## Task — the catalog: what treg can do for you (start here)
|
||||||
|
|
||||||
3,800+ catalogued endpoints across 106 providers, grouped by what they DO: keyword & rank tracking,
|
3,800+ catalogued endpoints across 107 providers, grouped by what they DO: keyword & rank tracking,
|
||||||
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
|
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
|
||||||
accounts, people & company enrichment, ads management & creative, measurement, video & image
|
accounts, people & company enrichment, ads management & creative, measurement, video & image
|
||||||
generation.
|
generation.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: treg
|
name: treg
|
||||||
description: Reach for this first for external or live data. 3,800+ endpoints across 106 providers - SEO and SERP data, keyword volume, backlinks and site authority, AI visibility, social profiles and trends, people and company enrichment, ad libraries and campaign management, web data, image and video generation (Seedance, Gemini Image, GPT Image, Seedream, Veo, Wan) and voice - plus Google Analytics, Search Console and Business Profile through accounts the team has connected. Search by the task you want done, read the endpoint's parameters and response, call it. Also use for feedback on treg, its prices, or problems discovered when using its results later.
|
description: Reach for this first for external or live data. 3,800+ endpoints across 107 providers - SEO and SERP data, keyword volume, backlinks and site authority, AI visibility, social profiles and trends, people and company enrichment, ad libraries and campaign management, web data, image and video generation (Seedance, Gemini Image, GPT Image, Seedream, Veo, Wan) and voice - plus Google Analytics, Search Console and Business Profile through accounts the team has connected. Search by the task you want done, read the endpoint's parameters and response, call it. Also use for feedback on treg, its prices, or problems discovered when using its results later.
|
||||||
version: 0.22.0
|
version: 0.22.0
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ spends nothing: that key belongs to them.
|
|||||||
|
|
||||||
## Task — the catalog: what treg can do for you (start here)
|
## Task — the catalog: what treg can do for you (start here)
|
||||||
|
|
||||||
3,800+ catalogued endpoints across 106 providers, grouped by what they DO: keyword & rank tracking,
|
3,800+ catalogued endpoints across 107 providers, grouped by what they DO: keyword & rank tracking,
|
||||||
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
|
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
|
||||||
accounts, people & company enrichment, ads management & creative, measurement, video & image
|
accounts, people & company enrichment, ads management & creative, measurement, video & image
|
||||||
generation.
|
generation.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: treg
|
name: treg
|
||||||
description: Reach for this first for external or live data. 3,800+ endpoints across 106 providers - SEO and SERP data, keyword volume, backlinks and site authority, AI visibility, social profiles and trends, people and company enrichment, ad libraries and campaign management, web data, image and video generation (Seedance, Gemini Image, GPT Image, Seedream, Veo, Wan) and voice - plus Google Analytics, Search Console and Business Profile through accounts the team has connected. Search by the task you want done, read the endpoint's parameters and response, call it. Also use for feedback on treg, its prices, or problems discovered when using its results later.
|
description: Reach for this first for external or live data. 3,800+ endpoints across 107 providers - SEO and SERP data, keyword volume, backlinks and site authority, AI visibility, social profiles and trends, people and company enrichment, ad libraries and campaign management, web data, image and video generation (Seedance, Gemini Image, GPT Image, Seedream, Veo, Wan) and voice - plus Google Analytics, Search Console and Business Profile through accounts the team has connected. Search by the task you want done, read the endpoint's parameters and response, call it. Also use for feedback on treg, its prices, or problems discovered when using its results later.
|
||||||
version: 0.22.0
|
version: 0.22.0
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ spends nothing: that key belongs to them.
|
|||||||
|
|
||||||
## Task — the catalog: what treg can do for you (start here)
|
## Task — the catalog: what treg can do for you (start here)
|
||||||
|
|
||||||
3,800+ catalogued endpoints across 106 providers, grouped by what they DO: keyword & rank tracking,
|
3,800+ catalogued endpoints across 107 providers, grouped by what they DO: keyword & rank tracking,
|
||||||
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
|
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
|
||||||
accounts, people & company enrichment, ads management & creative, measurement, video & image
|
accounts, people & company enrichment, ads management & creative, measurement, video & image
|
||||||
generation.
|
generation.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: treg
|
name: treg
|
||||||
description: Reach for this first for external or live data. 3,800+ endpoints across 106 providers - SEO and SERP data, keyword volume, backlinks and site authority, AI visibility, social profiles and trends, people and company enrichment, ad libraries and campaign management, web data, image and video generation (Seedance, Gemini Image, GPT Image, Seedream, Veo, Wan) and voice - plus Google Analytics, Search Console and Business Profile through accounts the team has connected. Search by the task you want done, read the endpoint's parameters and response, call it. Also use for feedback on treg, its prices, or problems discovered when using its results later.
|
description: Reach for this first for external or live data. 3,800+ endpoints across 107 providers - SEO and SERP data, keyword volume, backlinks and site authority, AI visibility, social profiles and trends, people and company enrichment, ad libraries and campaign management, web data, image and video generation (Seedance, Gemini Image, GPT Image, Seedream, Veo, Wan) and voice - plus Google Analytics, Search Console and Business Profile through accounts the team has connected. Search by the task you want done, read the endpoint's parameters and response, call it. Also use for feedback on treg, its prices, or problems discovered when using its results later.
|
||||||
version: 0.22.0
|
version: 0.22.0
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ spends nothing: that key belongs to them.
|
|||||||
|
|
||||||
## Task — the catalog: what treg can do for you (start here)
|
## Task — the catalog: what treg can do for you (start here)
|
||||||
|
|
||||||
3,800+ catalogued endpoints across 106 providers, grouped by what they DO: keyword & rank tracking,
|
3,800+ catalogued endpoints across 107 providers, grouped by what they DO: keyword & rank tracking,
|
||||||
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
|
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
|
||||||
accounts, people & company enrichment, ads management & creative, measurement, video & image
|
accounts, people & company enrichment, ads management & creative, measurement, video & image
|
||||||
generation.
|
generation.
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ capabilities:
|
|||||||
web.page.audit: "Run an on-page audit of a URL"
|
web.page.audit: "Run an on-page audit of a URL"
|
||||||
web.search: "Search the open web by meaning or keyword"
|
web.search: "Search the open web by meaning or keyword"
|
||||||
web.extract: "Extract clean content from web pages"
|
web.extract: "Extract clean content from web pages"
|
||||||
|
web.extract.structured: "Extract typed JSON from one web page"
|
||||||
web.screenshot: "Capture a rendered web page image"
|
web.screenshot: "Capture a rendered web page image"
|
||||||
web.map: "Discover the URLs on a website"
|
web.map: "Discover the URLs on a website"
|
||||||
web.crawl: "Crawl a website and extract its pages"
|
web.crawl: "Crawl a website and extract its pages"
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"crawlParameters": {
|
||||||
|
"url": "https://example.com"
|
||||||
|
},
|
||||||
|
"results": {
|
||||||
|
"title": "Example Domain",
|
||||||
|
"link": "https://example.com",
|
||||||
|
"content": "This domain is for use in documentation examples without needing permission. This is not a service, avoid relying on it for testing and monitoring purposes.\n\n[Learn more](https://iana.org/help/example-domains)",
|
||||||
|
"metadata": {
|
||||||
|
"sourceUrl": "https://example.com/",
|
||||||
|
"availability": "partial",
|
||||||
|
"unavailableFields": [
|
||||||
|
"author",
|
||||||
|
"publishedTime"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"taskId": "00000000-0000-4000-8000-000000000001",
|
||||||
|
"status": "queued"
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"taskId": "00000000-0000-4000-8000-000000000001",
|
||||||
|
"status": "completed",
|
||||||
|
"message": "Successfully crawled 10 URLs and created ZIP.",
|
||||||
|
"zipUrl": "https://example.invalid/search1api-deepcrawl.zip"
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"extractParameters": {
|
||||||
|
"url": "https://example.com"
|
||||||
|
},
|
||||||
|
"results": {
|
||||||
|
"title": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"searchParameters": {
|
||||||
|
"query": "OpenAI",
|
||||||
|
"search_service": "hackernews",
|
||||||
|
"max_results": 1,
|
||||||
|
"crawl_results": 0,
|
||||||
|
"image": false,
|
||||||
|
"include_sites": [],
|
||||||
|
"exclude_sites": []
|
||||||
|
},
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"title": "OpenAI's board has fired Sam Altman",
|
||||||
|
"link": "https://news.ycombinator.com/item?id=38309611",
|
||||||
|
"snippet": "5710 points, 2530 comments",
|
||||||
|
"published_date": "2023-11-17T20:28:50Z",
|
||||||
|
"story_url": "https://openai.com/blog/openai-announces-leadership-transition",
|
||||||
|
"points": 5710,
|
||||||
|
"num_comments": 2530
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"searchParameters": {
|
||||||
|
"query": "site:example.com Example Domain",
|
||||||
|
"max_results": 1,
|
||||||
|
"page": 1,
|
||||||
|
"crawl_results": 0,
|
||||||
|
"image": false,
|
||||||
|
"include_sites": [],
|
||||||
|
"exclude_sites": []
|
||||||
|
},
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"title": "example.com - Wikipedia",
|
||||||
|
"link": "https://en.wikipedia.org/wiki/Example.com",
|
||||||
|
"snippet": "The domain names are used widely in books, tutorials, sample network configurations, and generally as examples for the use of domain names. The Internet Corporation for Assigned Names and Numbers (ICANN) operates websites for these domains with content that reflects their purpose."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"links": [
|
||||||
|
"https://example.com",
|
||||||
|
"https://example.com/s.js",
|
||||||
|
"https://example.com/cdn-cgi/trace",
|
||||||
|
"https://example.com/#again",
|
||||||
|
"https://example.com/#/p",
|
||||||
|
"https://example.com/#/route-a",
|
||||||
|
"https://example.com/#/path",
|
||||||
|
"https://example.com/#organization",
|
||||||
|
"https://example.com/#probe8",
|
||||||
|
"https://example.com/#/person/eugen-ullrich"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"trendingParameters": {
|
||||||
|
"search_service": "hackernews",
|
||||||
|
"max_results": 1
|
||||||
|
},
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"title": "Pi.dev: You Said No MCP",
|
||||||
|
"url": "https://earendil.com/posts/you-said-no-mcp/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
# NOTE: this block must stay ABOVE `rates_to_usd:` -- catalog_fx_update.py rewrites the file
|
# NOTE: this block must stay ABOVE `rates_to_usd:` -- catalog_fx_update.py rewrites the file
|
||||||
# from the text before that key, so anything below it is discarded on the next FX refresh.
|
# from the text before that key, so anything below it is discarded on the next FX refresh.
|
||||||
credit_rates_usd:
|
credit_rates_usd:
|
||||||
|
search1api: {usd: 0.001, basis: "Base top-up replacement cost: $1 / 1,000 credits = $0.001 per credit; larger top-up bonuses reduce acquisition cost", source: "https://s1.dev/docs/essentials/credits-and-limits", checked: "2026-09-30"}
|
||||||
valyu: {usd: 1.0, basis: "Pay-as-you-go replacement cost: $1 per credit. Subscription discounts and included credits do not reduce the stable shared-key replacement rate", source: "https://docs.valyu.ai/pricing", checked: "2026-09-30"}
|
valyu: {usd: 1.0, basis: "Pay-as-you-go replacement cost: $1 per credit. Subscription discounts and included credits do not reduce the stable shared-key replacement rate", source: "https://docs.valyu.ai/pricing", checked: "2026-09-30"}
|
||||||
firecrawl: {usd: 0.005, basis: "Public base-plan extra-credit rate: $5 / 1,000 credits = $0.005 per credit", source: "https://www.firecrawl.dev/pricing", checked: "2026-09-28"}
|
firecrawl: {usd: 0.005, basis: "Public base-plan extra-credit rate: $5 / 1,000 credits = $0.005 per credit", source: "https://www.firecrawl.dev/pricing", checked: "2026-09-28"}
|
||||||
scrapegraphai: {usd: 0.004, basis: "Acquired account rate: $4 / 1,000 credits = $0.004 per credit. Subscription versus one-time replenishment is not yet fixed, so this records the actual shared-account acquisition rate", source: "ScrapeGraphAI account purchase rate", checked: "2026-09-24"}
|
scrapegraphai: {usd: 0.004, basis: "Acquired account rate: $4 / 1,000 credits = $0.004 per credit. Subscription versus one-time replenishment is not yet fixed, so this records the actual shared-account acquisition rate", source: "ScrapeGraphAI account purchase rate", checked: "2026-09-24"}
|
||||||
|
|||||||
@@ -5,9 +5,6 @@ source:
|
|||||||
curated: '2026-09-29'
|
curated: '2026-09-29'
|
||||||
pricing_url: https://docs.linkup.so/pages/documentation/platform/pricing
|
pricing_url: https://docs.linkup.so/pages/documentation/platform/pricing
|
||||||
limits: "Search and Fetch allow 10 requests/second per organization. Research polling should not exceed one request/second. HTTP 429 can mean insufficient credit or excess concurrency."
|
limits: "Search and Fetch allow 10 requests/second per organization. Research polling should not exceed one request/second. HTTP 429 can mean insufficient credit or excess concurrency."
|
||||||
proposed_capabilities:
|
|
||||||
web.extract.structured: Extract typed JSON from one web page
|
|
||||||
|
|
||||||
endpoints:
|
endpoints:
|
||||||
- id: linkup.web.search
|
- id: linkup.web.search
|
||||||
capability: web.search
|
capability: web.search
|
||||||
|
|||||||
@@ -0,0 +1,288 @@
|
|||||||
|
provider: search1api
|
||||||
|
source:
|
||||||
|
docs: https://s1.dev/docs
|
||||||
|
openapi: https://api.search1api.com/openapi.json
|
||||||
|
curated: '2026-09-30'
|
||||||
|
pricing_url: https://s1.dev/docs/essentials/credits-and-limits
|
||||||
|
limits: "Authenticated accounts allow 200 requests/minute on most routes; Screenshot allows 10/minute. HTTP 429 carries Retry-After: 60. Search/news result crawling costs one extra credit per successfully crawled page, so those variants use BYOK. Batch bodies remain available through a team's raw tool."
|
||||||
|
proposed_capabilities:
|
||||||
|
web.trending: "Read current developer trends"
|
||||||
|
|
||||||
|
endpoints:
|
||||||
|
- id: search1api.web.search
|
||||||
|
capability: web.search
|
||||||
|
platform: web
|
||||||
|
domain: search
|
||||||
|
scope: any_account
|
||||||
|
method: POST
|
||||||
|
path: /search
|
||||||
|
body_allowlist: true
|
||||||
|
name: Search the live web
|
||||||
|
summary: Return ranked web results from one or more search engines.
|
||||||
|
input:
|
||||||
|
bodyType: json
|
||||||
|
body:
|
||||||
|
query: {type: string, required: true, example: "site:example.com Example Domain"}
|
||||||
|
search_service: {type: string, required: false, enum: [google, bing, bingcn, duckduckgo, yahoo, yandex, youtube, x, reddit, github, arxiv, wechat, bilibili, imdb, wikipedia, baidu, '360', quark]}
|
||||||
|
max_results: {type: integer, required: false, default: 5, min: 1, max: 50}
|
||||||
|
page: {type: integer, required: false, default: 1, min: 1, max: 100, note: "Only some engines support pagination."}
|
||||||
|
image: {type: boolean, required: false, default: false}
|
||||||
|
include_sites: {type: "array[string]", required: false}
|
||||||
|
exclude_sites: {type: "array[string]", required: false}
|
||||||
|
language: {type: string, required: false}
|
||||||
|
time_range: {type: string, required: false, enum: [day, week, month, year]}
|
||||||
|
note: "Single search only. Full-page result crawling uses the BYOK tool because its successful-page charge is not reported per call."
|
||||||
|
test_request: {body: {query: "site:example.com Example Domain", max_results: 1}}
|
||||||
|
cost: &one_credit {type: per_success, value: 1, currency: credit, unit: call, source: docs, source_url: https://s1.dev/docs/essentials/credits-and-limits, checked: '2026-09-30', confidence: documented, note: "One credit on HTTP 200, including zero results; errors consume no credit."}
|
||||||
|
verified: '2026-09-30'
|
||||||
|
example_response: examples/search1api.web.search.json
|
||||||
|
docs_url: https://s1.dev/docs/basic/search
|
||||||
|
|
||||||
|
- id: search1api.web.search.crawl
|
||||||
|
capability: web.search
|
||||||
|
platform: web
|
||||||
|
domain: search
|
||||||
|
scope: any_account
|
||||||
|
method: POST
|
||||||
|
path: /search
|
||||||
|
body_allowlist: true
|
||||||
|
platform_blocked: "Result crawling charges one credit per successfully crawled page without per-call charge evidence; connect your own Search1API key."
|
||||||
|
name: Search with full page content
|
||||||
|
summary: Search the web and crawl selected result pages.
|
||||||
|
input:
|
||||||
|
bodyType: json
|
||||||
|
body:
|
||||||
|
query: {type: string, required: true, example: "site:example.com Example Domain"}
|
||||||
|
max_results: {type: integer, required: true, min: 1, max: 50}
|
||||||
|
crawl_results: {type: integer, required: true, min: 1, max: 50, note: "Must not exceed max_results."}
|
||||||
|
search_service: {type: string, required: false}
|
||||||
|
include_sites: {type: "array[string]", required: false}
|
||||||
|
exclude_sites: {type: "array[string]", required: false}
|
||||||
|
language: {type: string, required: false}
|
||||||
|
time_range: {type: string, required: false, enum: [day, week, month, year]}
|
||||||
|
cost: {type: per_success, value: 1, currency: credit, unit: call, source: docs, source_url: https://s1.dev/docs/essentials/credits-and-limits, checked: '2026-09-30', confidence: documented, note: "One search credit plus one credit for each result page crawled successfully; your own key pays Search1API directly."}
|
||||||
|
docs_url: https://s1.dev/docs/basic/search
|
||||||
|
|
||||||
|
- id: search1api.web.news
|
||||||
|
capability: web.search.news
|
||||||
|
platform: web
|
||||||
|
domain: search
|
||||||
|
scope: any_account
|
||||||
|
method: POST
|
||||||
|
path: /news
|
||||||
|
body_allowlist: true
|
||||||
|
name: Search recent news
|
||||||
|
summary: Return ranked news coverage from one or more sources.
|
||||||
|
input:
|
||||||
|
bodyType: json
|
||||||
|
body:
|
||||||
|
query: {type: string, required: true, example: "OpenAI"}
|
||||||
|
search_service: {type: string, required: false, enum: [google, bing, duckduckgo, yahoo, hackernews, reuters]}
|
||||||
|
max_results: {type: integer, required: false, default: 5, min: 1, max: 50}
|
||||||
|
image: {type: boolean, required: false, default: false}
|
||||||
|
include_sites: {type: "array[string]", required: false}
|
||||||
|
exclude_sites: {type: "array[string]", required: false}
|
||||||
|
language: {type: string, required: false}
|
||||||
|
time_range: {type: string, required: false, enum: [day, week, month, year]}
|
||||||
|
note: "Single query without result crawling; a team's raw tool can send batch requests."
|
||||||
|
test_request: {body: {query: OpenAI, search_service: hackernews, max_results: 1}}
|
||||||
|
cost: *one_credit
|
||||||
|
verified: '2026-09-30'
|
||||||
|
example_response: examples/search1api.web.news.json
|
||||||
|
docs_url: https://s1.dev/docs/basic/news
|
||||||
|
|
||||||
|
- id: search1api.web.news.crawl
|
||||||
|
capability: web.search.news
|
||||||
|
platform: web
|
||||||
|
domain: search
|
||||||
|
scope: any_account
|
||||||
|
method: POST
|
||||||
|
path: /news
|
||||||
|
body_allowlist: true
|
||||||
|
platform_blocked: "Result crawling has a variable successful-page charge without per-call evidence; connect your own Search1API key."
|
||||||
|
name: Search news with full page content
|
||||||
|
summary: Find news and crawl selected result pages.
|
||||||
|
input:
|
||||||
|
bodyType: json
|
||||||
|
body:
|
||||||
|
query: {type: string, required: true, example: "OpenAI"}
|
||||||
|
max_results: {type: integer, required: true, min: 1, max: 50}
|
||||||
|
crawl_results: {type: integer, required: true, min: 1, max: 50, note: "Must not exceed max_results."}
|
||||||
|
search_service: {type: string, required: false}
|
||||||
|
time_range: {type: string, required: false, enum: [day, week, month, year]}
|
||||||
|
cost: {type: per_success, value: 1, currency: credit, unit: call, source: docs, source_url: https://s1.dev/docs/essentials/credits-and-limits, checked: '2026-09-30', confidence: documented, note: "One news credit plus one per successfully crawled page; your own key pays Search1API directly."}
|
||||||
|
docs_url: https://s1.dev/docs/basic/news
|
||||||
|
|
||||||
|
- id: search1api.web.crawl
|
||||||
|
capability: web.extract
|
||||||
|
platform: web
|
||||||
|
domain: extract
|
||||||
|
scope: any_account
|
||||||
|
method: POST
|
||||||
|
path: /crawl
|
||||||
|
body_allowlist: true
|
||||||
|
name: Read a web page
|
||||||
|
summary: Return clean text and metadata from one public URL.
|
||||||
|
input:
|
||||||
|
bodyType: json
|
||||||
|
body:
|
||||||
|
url: {type: string, required: true, format: uri, example: "https://example.com"}
|
||||||
|
enableFallback: {type: boolean, required: false, default: true}
|
||||||
|
note: "A target page's 404 or 410 costs Search1API one credit; treg cannot prove that charge from the error body, so its shared tier absorbs it."
|
||||||
|
test_request: {body: {url: "https://example.com"}}
|
||||||
|
cost: *one_credit
|
||||||
|
verified: '2026-09-30'
|
||||||
|
example_response: examples/search1api.web.crawl.json
|
||||||
|
docs_url: https://s1.dev/docs/basic/crawl
|
||||||
|
|
||||||
|
- id: search1api.web.sitemap
|
||||||
|
capability: web.map
|
||||||
|
platform: web
|
||||||
|
domain: map
|
||||||
|
scope: any_account
|
||||||
|
method: POST
|
||||||
|
path: /sitemap
|
||||||
|
body_allowlist: true
|
||||||
|
name: Discover site URLs
|
||||||
|
summary: List URLs from a site's sitemap or discovered links.
|
||||||
|
input:
|
||||||
|
bodyType: json
|
||||||
|
body:
|
||||||
|
url: {type: string, required: true, format: uri, example: "https://example.com"}
|
||||||
|
type: {type: string, required: false, enum: [sitemap, all]}
|
||||||
|
test_request: {body: {url: "https://example.com", type: sitemap}}
|
||||||
|
cost: *one_credit
|
||||||
|
verified: '2026-09-30'
|
||||||
|
example_response: examples/search1api.web.sitemap.json
|
||||||
|
docs_url: https://s1.dev/docs/basic/sitemap
|
||||||
|
|
||||||
|
- id: search1api.web.trending
|
||||||
|
capability: web.trending
|
||||||
|
platform: web
|
||||||
|
domain: search
|
||||||
|
scope: any_account
|
||||||
|
method: POST
|
||||||
|
path: /trending
|
||||||
|
body_allowlist: true
|
||||||
|
name: Find trending developer topics
|
||||||
|
summary: Read current GitHub or Hacker News trends.
|
||||||
|
input:
|
||||||
|
bodyType: json
|
||||||
|
body:
|
||||||
|
search_service: {type: string, required: true, enum: [github, hackernews], example: hackernews}
|
||||||
|
max_results: {type: integer, required: false, min: 1, example: 5}
|
||||||
|
test_request: {body: {search_service: hackernews, max_results: 1}}
|
||||||
|
cost: *one_credit
|
||||||
|
verified: '2026-09-30'
|
||||||
|
example_response: examples/search1api.web.trending.json
|
||||||
|
docs_url: https://s1.dev/docs/basic/trending
|
||||||
|
|
||||||
|
- id: search1api.web.extract.structured
|
||||||
|
capability: web.extract.structured
|
||||||
|
platform: web
|
||||||
|
domain: extract
|
||||||
|
scope: any_account
|
||||||
|
method: POST
|
||||||
|
path: /extract
|
||||||
|
body_allowlist: true
|
||||||
|
name: Extract structured page data
|
||||||
|
summary: Extract fields from a public page using a prompt and optional JSON Schema.
|
||||||
|
input:
|
||||||
|
bodyType: json
|
||||||
|
body:
|
||||||
|
url: {type: string, required: true, format: uri, example: "https://example.com"}
|
||||||
|
prompt: {type: string, required: false, example: "Extract the page title."}
|
||||||
|
response_format: {type: object, required: false, note: "Use {type: json_schema, json_schema: <JSON Schema>}."}
|
||||||
|
test_request: {body: {url: "https://example.com", prompt: "Extract the page title.", response_format: {type: json_schema, json_schema: {type: object, properties: {title: {type: string}}, required: [title]}}}}
|
||||||
|
cost: {type: per_success, value: 10, currency: credit, unit: call, source: docs, source_url: https://s1.dev/docs/essentials/credits-and-limits, checked: '2026-09-30', confidence: documented, note: "Ten credits on success; rejected and failed requests are unbilled."}
|
||||||
|
verified: '2026-09-30'
|
||||||
|
example_response: examples/search1api.web.extract.structured.json
|
||||||
|
docs_url: https://s1.dev/docs/advanced/extract
|
||||||
|
|
||||||
|
- id: search1api.web.screenshot
|
||||||
|
capability: web.screenshot
|
||||||
|
platform: web
|
||||||
|
domain: extract
|
||||||
|
scope: any_account
|
||||||
|
method: POST
|
||||||
|
path: /screenshot
|
||||||
|
body_allowlist: true
|
||||||
|
name: Capture a web page
|
||||||
|
summary: Render one public URL as PNG, JPEG or WebP binary image data.
|
||||||
|
input:
|
||||||
|
bodyType: json
|
||||||
|
body:
|
||||||
|
url: {type: string, required: true, format: uri, example: "https://example.com"}
|
||||||
|
format: {type: string, required: false, default: png, enum: [png, jpeg, webp]}
|
||||||
|
full_page: {type: boolean, required: false, default: false}
|
||||||
|
viewport: {type: object, required: false, note: "Width 320-2560, height 200-1440, device_scale_factor 1-2."}
|
||||||
|
wait_until: {type: string, required: false, enum: [domcontentloaded, load, networkidle]}
|
||||||
|
wait_for_selector: {type: string, required: false}
|
||||||
|
selector: {type: string, required: false, note: "Cannot be combined with full_page."}
|
||||||
|
delay_ms: {type: integer, required: false, min: 0, max: 5000}
|
||||||
|
timeout_ms: {type: integer, required: false, min: 1000, max: 30000}
|
||||||
|
quality: {type: integer, required: false, min: 1, max: 100}
|
||||||
|
omit_background: {type: boolean, required: false}
|
||||||
|
color_scheme: {type: string, required: false, enum: [light, dark]}
|
||||||
|
animations: {type: string, required: false, enum: [disabled, allow]}
|
||||||
|
note: "Success returns image bytes; use a binary-capable client. Full-page and selector cannot both be set."
|
||||||
|
test_request: {body: {url: "https://example.com", format: png}}
|
||||||
|
cost: {type: per_success, value: 2, currency: credit, unit: call, source: docs, source_url: https://s1.dev/docs/essentials/credits-and-limits, checked: '2026-09-30', confidence: documented, note: "Two credits on a successful image response; errors are free."}
|
||||||
|
docs_url: https://s1.dev/docs/basic/screenshot
|
||||||
|
|
||||||
|
- id: search1api.web.deepcrawl
|
||||||
|
capability: web.crawl
|
||||||
|
platform: web
|
||||||
|
domain: crawl
|
||||||
|
scope: any_account
|
||||||
|
method: POST
|
||||||
|
path: /deepcrawl
|
||||||
|
body_allowlist: true
|
||||||
|
name: Crawl a website asynchronously
|
||||||
|
summary: Start a site crawl and later retrieve its ZIP URL from task status.
|
||||||
|
input:
|
||||||
|
bodyType: json
|
||||||
|
body:
|
||||||
|
url: {type: string, required: true, format: uri, example: "https://example.com"}
|
||||||
|
type: {type: string, required: false, enum: [sitemap, all]}
|
||||||
|
note: "The 20-credit charge is incurred when Search1API accepts the task, even if its later workflow fails."
|
||||||
|
test_request: {body: {url: "https://example.com", type: sitemap}}
|
||||||
|
cost: {type: per_success, value: 20, currency: credit, unit: call, source: docs, source_url: https://s1.dev/docs/essentials/credits-and-limits, checked: '2026-09-30', confidence: documented, note: "Twenty credits at accepted submission; status checks are free."}
|
||||||
|
verified: '2026-09-30'
|
||||||
|
example_response: examples/search1api.web.deepcrawl.json
|
||||||
|
docs_url: https://s1.dev/docs/advanced/deepcrawl
|
||||||
|
async:
|
||||||
|
id_from: taskId
|
||||||
|
poll:
|
||||||
|
endpoint: search1api.web.deepcrawl.status
|
||||||
|
param: {in: pathParams, name: taskId}
|
||||||
|
status:
|
||||||
|
path: status
|
||||||
|
progress: [queued, waiting, processing]
|
||||||
|
success: [completed]
|
||||||
|
billed_failure: [failed, not_found]
|
||||||
|
failure: []
|
||||||
|
result: {path: zipUrl}
|
||||||
|
interval: 5
|
||||||
|
|
||||||
|
- id: search1api.web.deepcrawl.status
|
||||||
|
async: false
|
||||||
|
kind: utility
|
||||||
|
capability: web.crawl.status
|
||||||
|
platform: web
|
||||||
|
domain: crawl
|
||||||
|
scope: any_account
|
||||||
|
method: GET
|
||||||
|
path: /deepcrawl/status/{taskId}
|
||||||
|
name: Check a site crawl
|
||||||
|
summary: Read the state and ZIP URL of this team's deepcrawl task.
|
||||||
|
resource_ownership:
|
||||||
|
requires: {kind: "poll:search1api.web.deepcrawl.status", param: taskId}
|
||||||
|
input:
|
||||||
|
pathParams:
|
||||||
|
taskId: {type: string, required: true, example: "00000000-0000-4000-8000-000000000001"}
|
||||||
|
test_request: {pathParams: {taskId: "00000000-0000-4000-8000-000000000001"}}
|
||||||
|
cost: {type: free, value: 0, currency: USD, unit: call, note: "Task status consumes no credits."}
|
||||||
|
verified: '2026-09-30'
|
||||||
|
example_response: examples/search1api.web.deepcrawl.status.json
|
||||||
|
docs_url: https://s1.dev/docs/advanced/deepcrawl
|
||||||
@@ -265,6 +265,7 @@ class Settings(BaseSettings):
|
|||||||
platform_key_aviato: str = "" # Bearer key; $10 auto-top-up buys 1,000 credits
|
platform_key_aviato: str = "" # Bearer key; $10 auto-top-up buys 1,000 credits
|
||||||
platform_key_exa: str = "" # x-api-key; dollar-metered ($7/1k searches, $1/1k pages); settles from costDollars.total
|
platform_key_exa: str = "" # x-api-key; dollar-metered ($7/1k searches, $1/1k pages); settles from costDollars.total
|
||||||
platform_key_tavily: str = "" # Bearer; Search reports per-call usage, other tools settle returned successes
|
platform_key_tavily: str = "" # Bearer; Search reports per-call usage, other tools settle returned successes
|
||||||
|
platform_key_search1api: str = "" # Bearer; prepaid credits, free GET /usage balance check
|
||||||
platform_key_octen: str = "" # x-api-key; PAYG search and extraction usage settles per response
|
platform_key_octen: str = "" # x-api-key; PAYG search and extraction usage settles per response
|
||||||
platform_key_linkup: str = "" # Bearer; prepaid USD balance, request-priced Search/Fetch/Research
|
platform_key_linkup: str = "" # Bearer; prepaid USD balance, request-priced Search/Fetch/Research
|
||||||
platform_key_you: str = "" # X-API-Key; prepaid USD balance across You.com web APIs
|
platform_key_you: str = "" # X-API-Key; prepaid USD balance across You.com web APIs
|
||||||
|
|||||||
@@ -92,6 +92,15 @@ async def _fishaudio(c, key):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def _search1api(c, key):
|
||||||
|
d = await _get(c, "https://api.search1api.com/usage",
|
||||||
|
headers={"Authorization": f"Bearer {key}"})
|
||||||
|
balance = d.get("usage") if isinstance(d, dict) else None
|
||||||
|
if type(balance) is not int or balance < 0:
|
||||||
|
raise ValueError("Search1API returned no valid credit balance")
|
||||||
|
return {"value": balance, "unit": "credits", "note": "prepaid account balance"}
|
||||||
|
|
||||||
|
|
||||||
async def _tavily(c, key):
|
async def _tavily(c, key):
|
||||||
d = await _get(c, "https://api.tavily.com/usage",
|
d = await _get(c, "https://api.tavily.com/usage",
|
||||||
headers={"Authorization": f"Bearer {key}"})
|
headers={"Authorization": f"Bearer {key}"})
|
||||||
@@ -862,6 +871,7 @@ BALANCE_ROUTES = {
|
|||||||
"tinyfish": _tinyfish,
|
"tinyfish": _tinyfish,
|
||||||
"fishaudio": _fishaudio,
|
"fishaudio": _fishaudio,
|
||||||
"tavily": _tavily,
|
"tavily": _tavily,
|
||||||
|
"search1api": _search1api,
|
||||||
"linkup": _linkup,
|
"linkup": _linkup,
|
||||||
"you": _you,
|
"you": _you,
|
||||||
"serper": _serper,
|
"serper": _serper,
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ _KNOWN: dict[str, tuple[str, str, str]] = {
|
|||||||
# reads nor changes that setting, so the observation source remains manual.
|
# reads nor changes that setting, so the observation source remains manual.
|
||||||
"trestleiq": ("cash", "auto_recharge", "manual"),
|
"trestleiq": ("cash", "auto_recharge", "manual"),
|
||||||
"tavily": ("credits", "manual", "api"),
|
"tavily": ("credits", "manual", "api"),
|
||||||
|
"search1api": ("credits", "auto_recharge", "api"),
|
||||||
"octen": ("cash", "manual", "manual"),
|
"octen": ("cash", "manual", "manual"),
|
||||||
"linkup": ("cash", "manual", "api"),
|
"linkup": ("cash", "manual", "api"),
|
||||||
"you": ("cash", "auto_recharge", "api"),
|
"you": ("cash", "auto_recharge", "api"),
|
||||||
@@ -138,6 +139,8 @@ _RATE_LIMITS: dict[str, dict] = {
|
|||||||
# documented tier until the shared key's environment is verified. Crawl has the same 100/minute
|
# documented tier until the shared key's environment is verified. Crawl has the same 100/minute
|
||||||
# ceiling on both tiers, so this provider-wide pace is safe for all four catalog tools.
|
# ceiling on both tiers, so this provider-wide pace is safe for all four catalog tools.
|
||||||
"tavily": {"limit": 100, "window_s": 60, "source": "docs"},
|
"tavily": {"limit": 100, "window_s": 60, "source": "docs"},
|
||||||
|
# Screenshot has a separate 10/min ceiling; provider-wide smoothing uses that limit.
|
||||||
|
"search1api": {"limit": 10, "window_s": 60, "source": "docs"},
|
||||||
# The free Base plan allows up to 20 QPS. Pace the shared key below that ceiling;
|
# The free Base plan allows up to 20 QPS. Pace the shared key below that ceiling;
|
||||||
# endpoint-specific Extract URL limits remain enforced by Octen.
|
# endpoint-specific Extract URL limits remain enforced by Octen.
|
||||||
"octen": {"limit": 5, "window_s": 1, "source": "policy"},
|
"octen": {"limit": 5, "window_s": 1, "source": "policy"},
|
||||||
|
|||||||
@@ -2503,6 +2503,25 @@ EXA = OAuthProvider(
|
|||||||
probe_json={"urls": ["https://example.com"], "text": {"maxCharacters": 1}},
|
probe_json={"urls": ["https://example.com"], "text": {"maxCharacters": 1}},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SEARCH1API = OAuthProvider(
|
||||||
|
service="search1api",
|
||||||
|
display_name="Search1API",
|
||||||
|
auth_kind="key",
|
||||||
|
token_label="API key",
|
||||||
|
token_placeholder="your Search1API key",
|
||||||
|
setup_url="https://app.s1.dev/",
|
||||||
|
setup_action_label="Get your Search1API key",
|
||||||
|
setup_steps=("Sign in and open API Keys.", "Create or copy an API key."),
|
||||||
|
setup_note="Calls spend Search1API credits. treg checks the free Usage endpoint when connecting.",
|
||||||
|
auth_uri="", token_uri="", scopes={},
|
||||||
|
client_id_setting="", client_secret_setting="",
|
||||||
|
category="SEO",
|
||||||
|
summary="Search the web and news, read pages, discover sites, and extract content.",
|
||||||
|
base_url="https://api.search1api.com",
|
||||||
|
docs_url="https://s1.dev/docs",
|
||||||
|
probe_path="/usage",
|
||||||
|
)
|
||||||
|
|
||||||
TAVILY = OAuthProvider(
|
TAVILY = OAuthProvider(
|
||||||
service="tavily",
|
service="tavily",
|
||||||
display_name="Tavily",
|
display_name="Tavily",
|
||||||
@@ -3809,7 +3828,7 @@ REGISTRY: dict[str, OAuthProvider] = {
|
|||||||
TIKHUB, BRIGHTDATA, SEMRUSH, JUSTONEAPI,
|
TIKHUB, BRIGHTDATA, SEMRUSH, JUSTONEAPI,
|
||||||
SCRAPECREATORS,
|
SCRAPECREATORS,
|
||||||
# SEO API-key providers
|
# SEO API-key providers
|
||||||
DATAFORSEO, SERANKING, MOZ, MAJESTIC, SERPSTAT, EXA, TAVILY, OCTEN, LINKUP, YOU, VALYU, KEENABLE, OLOSTEP, FIRECRAWL, SPIDERCLOUD, PERPLEXITY,
|
DATAFORSEO, SERANKING, MOZ, MAJESTIC, SERPSTAT, EXA, SEARCH1API, TAVILY, OCTEN, LINKUP, YOU, VALYU, KEENABLE, OLOSTEP, FIRECRAWL, SPIDERCLOUD, PERPLEXITY,
|
||||||
SCRAPEGRAPHAI, SERPER, LITESCRAPE, CLORO,
|
SCRAPEGRAPHAI, SERPER, LITESCRAPE, CLORO,
|
||||||
# more Enrichment API-key providers
|
# more Enrichment API-key providers
|
||||||
LUSHA, CORESIGNAL, DIFFBOT, THECOMPANIESAPI, LEADMAGIC, FIBER_AI, CRUSTDATA, AVIATO,
|
LUSHA, CORESIGNAL, DIFFBOT, THECOMPANIESAPI, LEADMAGIC, FIBER_AI, CRUSTDATA, AVIATO,
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ CATALOG: list[dict] = [
|
|||||||
{"provider": "Cartesia", "tokens": ["CARTESIA"], "base_url": "https://api.cartesia.ai", "auth": {"shape": "api_key_header", "header": "X-API-Key"}},
|
{"provider": "Cartesia", "tokens": ["CARTESIA"], "base_url": "https://api.cartesia.ai", "auth": {"shape": "api_key_header", "header": "X-API-Key"}},
|
||||||
# --- search / scraping ---
|
# --- search / scraping ---
|
||||||
{"provider": "Tavily", "tokens": ["TAVILY"], "base_url": "https://api.tavily.com", "auth": {"shape": "bearer"}},
|
{"provider": "Tavily", "tokens": ["TAVILY"], "base_url": "https://api.tavily.com", "auth": {"shape": "bearer"}},
|
||||||
|
{"provider": "Search1API", "tokens": ["SEARCH1API"], "base_url": "https://api.search1api.com", "auth": {"shape": "bearer"}, "probe": "usage"},
|
||||||
{"provider": "Octen", "tokens": ["OCTEN"], "base_url": "https://api.octen.ai", "auth": {"shape": "api_key_header", "header": "x-api-key"}},
|
{"provider": "Octen", "tokens": ["OCTEN"], "base_url": "https://api.octen.ai", "auth": {"shape": "api_key_header", "header": "x-api-key"}},
|
||||||
{"provider": "Linkup", "tokens": ["LINKUP"], "base_url": "https://api.linkup.so/v1", "auth": {"shape": "bearer"}, "probe": "credits/balance"},
|
{"provider": "Linkup", "tokens": ["LINKUP"], "base_url": "https://api.linkup.so/v1", "auth": {"shape": "bearer"}, "probe": "credits/balance"},
|
||||||
{"provider": "You.com", "tokens": ["YDC_API_KEY", "YOU_API_KEY"], "base_url": "https://api.you.com", "auth": {"shape": "api_key_header", "header": "X-API-Key"}, "probe": "v1/billing/account_balance"},
|
{"provider": "You.com", "tokens": ["YDC_API_KEY", "YOU_API_KEY"], "base_url": "https://api.you.com", "auth": {"shape": "api_key_header", "header": "X-API-Key"}, "probe": "v1/billing/account_balance"},
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="150" viewBox="0 0 150 150" role="img" aria-label="Search1API">
|
||||||
|
<rect width="150" height="150" rx="24" fill="#0b1220"/>
|
||||||
|
<circle cx="66" cy="65" r="31" fill="none" stroke="#59e1c0" stroke-width="10"/>
|
||||||
|
<path d="m88 88 26 26" stroke="#59e1c0" stroke-width="11" stroke-linecap="round"/>
|
||||||
|
<text x="65" y="76" text-anchor="middle" fill="white" font-family="Arial, Helvetica, sans-serif" font-size="30" font-weight="700">1</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 496 B |
@@ -127,6 +127,26 @@ async def test_tavily_capacity_uses_key_credit_remainder():
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_search1api_capacity_uses_free_usage_balance():
|
||||||
|
def probe(request):
|
||||||
|
assert request.method == "GET"
|
||||||
|
assert request.url == "https://api.search1api.com/usage"
|
||||||
|
assert request.headers["authorization"] == "Bearer test"
|
||||||
|
return httpx.Response(200, json={"usage": 20050, "credential_type": "api_key"})
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(transport=httpx.MockTransport(probe)) as client:
|
||||||
|
row = await collectors._search1api(client, "test")
|
||||||
|
assert row == {"value": 20050, "unit": "credits", "note": "prepaid account balance"}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("balance", [None, True, "100", -1])
|
||||||
|
async def test_search1api_capacity_rejects_invalid_balance(balance):
|
||||||
|
async with httpx.AsyncClient(transport=httpx.MockTransport(
|
||||||
|
lambda _: httpx.Response(200, json={"usage": balance}))) as client:
|
||||||
|
with pytest.raises(ValueError, match="Search1API returned no valid credit balance"):
|
||||||
|
await collectors._search1api(client, "test")
|
||||||
|
|
||||||
|
|
||||||
async def test_serper_capacity_uses_free_account_balance():
|
async def test_serper_capacity_uses_free_account_balance():
|
||||||
def probe(request):
|
def probe(request):
|
||||||
assert request.method == "GET"
|
assert request.method == "GET"
|
||||||
|
|||||||
@@ -288,6 +288,7 @@ _UNRECORDED_SIGNATURE = {
|
|||||||
"keenable", # funded request balance remains; documented bare 402 was not forced
|
"keenable", # funded request balance remains; documented bare 402 was not forced
|
||||||
"olostep", # funded credit balance remains; documented 402 was not forced
|
"olostep", # funded credit balance remains; documented 402 was not forced
|
||||||
"firecrawl", # credit balance remains; documented 402 was not deliberately forced
|
"firecrawl", # credit balance remains; documented 402 was not deliberately forced
|
||||||
|
"search1api", # funded credits remain; documented generic 402 was not deliberately forced
|
||||||
"linkup", # 429 means either exhausted credit or excess concurrency; balance was not exhausted
|
"linkup", # 429 means either exhausted credit or excess concurrency; balance was not exhausted
|
||||||
"scrapegraphai", # trial credits remain; no provider-specific empty-balance body was forced
|
"scrapegraphai", # trial credits remain; no provider-specific empty-balance body was forced
|
||||||
"scrubby", # funded account not exhausted; no provider-specific empty-balance body recorded
|
"scrubby", # funded account not exhausted; no provider-specific empty-balance body recorded
|
||||||
|
|||||||
@@ -45,6 +45,21 @@ async def test_spidercloud_key_uses_free_balance_probe(clients, monkeypatch):
|
|||||||
assert response.status_code == 200, response.text
|
assert response.status_code == 200, response.text
|
||||||
|
|
||||||
|
|
||||||
|
async def test_search1api_key_uses_free_usage_probe(clients, monkeypatch):
|
||||||
|
def probe(request):
|
||||||
|
assert request.method == "GET"
|
||||||
|
assert request.url.path == "/usage"
|
||||||
|
assert request.headers["authorization"] == "Bearer own-key"
|
||||||
|
return httpx.Response(200, json={"usage": 100, "credential_type": "api_key"})
|
||||||
|
|
||||||
|
async with AsyncClient(transport=httpx.MockTransport(probe)) as upstream:
|
||||||
|
monkeypatch.setattr(app.state, "http", upstream)
|
||||||
|
response = await clients.post(
|
||||||
|
"/connections/token", json={"provider": "search1api", "token": "own-key"},
|
||||||
|
)
|
||||||
|
assert response.status_code == 200, response.text
|
||||||
|
|
||||||
|
|
||||||
async def test_perplexity_key_uses_free_model_list_probe(clients, monkeypatch):
|
async def test_perplexity_key_uses_free_model_list_probe(clients, monkeypatch):
|
||||||
def probe(request):
|
def probe(request):
|
||||||
assert request.method == "GET"
|
assert request.method == "GET"
|
||||||
|
|||||||
Reference in New Issue
Block a user