feat(catalog): add You.com BYOK and platform tools

This commit is contained in:
shehjad-dev
2026-09-29 16:57:08 +06:00
parent b021c99955
commit 46cafed765
25 changed files with 540 additions and 13 deletions
+6 -1
View File
@@ -270,6 +270,7 @@ Regenerate via `scripts/build-map.py`.
| `src/treg/catalog/apify.yaml` | architecture/catalog.md |
| `src/treg/catalog/aviato.yaml` | architecture/catalog.md |
| `src/treg/catalog/brightdata.yaml` | architecture/catalog.md |
| `src/treg/catalog/capabilities.yaml` | architecture/catalog.md |
| `src/treg/catalog/cloro.yaml` | architecture/catalog.md |
| `src/treg/catalog/companyenrich.yaml` | architecture/catalog.md |
| `src/treg/catalog/contracts.yaml` | architecture/catalog.md |
@@ -312,6 +313,8 @@ Regenerate via `scripts/build-map.py`.
| `src/treg/catalog/examples/wiza.people.email.find.terminal.json` | architecture/catalog.md |
| `src/treg/catalog/examples/wiza.people.phone.find.json` | architecture/catalog.md |
| `src/treg/catalog/examples/wiza.people.phone.find.terminal.json` | architecture/catalog.md |
| `src/treg/catalog/examples/you.web.contents.json` | architecture/catalog.md |
| `src/treg/catalog/examples/you.web.search.json` | architecture/catalog.md |
| `src/treg/catalog/fetchinio.yaml` | architecture/catalog.md |
| `src/treg/catalog/financialdatasets.yaml` | architecture/catalog.md |
| `src/treg/catalog/fishaudio.yaml` | architecture/catalog.md |
@@ -352,6 +355,7 @@ Regenerate via `scripts/build-map.py`.
| `src/treg/catalog/trestleiq.yaml` | architecture/catalog.md |
| `src/treg/catalog/trykitt.yaml` | architecture/catalog.md |
| `src/treg/catalog/wiza.yaml` | architecture/catalog.md |
| `src/treg/catalog/you.yaml` | architecture/catalog.md |
| `src/treg/cli.py` | architecture/hub.md, architecture/instagram-oauth.md, interface/cli.md, interface/onboarding.md, interface/shell.md |
| `src/treg/cli_analytics.py` | interface/cli.md |
| `src/treg/client_identity.py` | architecture/import-boundaries.md, architecture/proxy-model.md, interface/api.md |
@@ -515,6 +519,7 @@ Regenerate via `scripts/build-map.py`.
| `src/treg/web/logos/predictleads.svg` | interface/enrich-arena.md |
| `src/treg/web/logos/thecompaniesapi.svg` | interface/enrich-arena.md |
| `src/treg/web/logos/tomba.svg` | interface/enrich-arena.md |
| `src/treg/web/logos/you.svg` | architecture/catalog.md |
| `src/treg/web/media/astra/page.css` | interface/seo.md |
| `src/treg/web/media/astra/page.js` | interface/seo.md |
| `src/treg/web/media/jev/signals.json` | interface/seo.md |
@@ -630,7 +635,7 @@ Regenerate via `scripts/build-map.py`.
| `architecture/ads-conversions.md` | `adsconv.py`, `signup.py`, `adtrack.js`, `gtag.js` |
| `architecture/archive.md` | `archive.py`, `hunter.yaml`, `results.py`, `0031_archive_result_admission.py`, `test_cache_result_admission.py`, `archive_bodies.py`, `config.py`, `object_store.py`, `0032_archive_body_storage.py`, `test_archive_r2.py`, `fake_object_store.py`, `smoke_archive_r2.py`, `0002_archive_tables.py`, `0003_callrecord_cached.py`, `0004_archivekey_request_shape.py`, `0011_callrecord_archive_link.py`, `service.py`, `settle.py`, `0039_archive_own_key_and_repeat_pricing.py`, `backfill_call_archive_links.py`, `api.py`, `bootstrap.py`, `admin.py`, `asynctasks.py` |
| `architecture/auth-secrets.md` | `injectors.py`, `ssrf.py`, `crypto.py`, `oauth.py`, `__init__.py`, `authorization.py`, `oauth_flow.py`, `refresh.py`, `oauth_exchange.py`, `oauth_refresh.py`, `oauth_providers.py`, `session.js`, `keys.js`, `TeamPage.vue`, `health.py`, `connect.py`, `0051_context_dev_tool_host.py`, `connections.py`, `resources.py`, `__init__.py`, `bindings.py`, `bundles.py`, `api_keys.py`, `access.py`, `api_keys.py`, `test_api_keys.py`, `test_oauth_refresh.py`, `test_financialdatasets.py`, `test_key_providers.py`, `config.py` |
| `architecture/catalog.md` | `fetchinio.yaml`, `fetchinio.svg`, `fetchinio.linkedin.user.profile.json`, `fetchinio.linkedin.company.profile.json`, `fetchinio.linkedin.user.posts.json`, `fetchinio.linkedin.user.reactions.json`, `fetchinio.linkedin.post.comments.json`, `fetchinio.linkedin.post.reactions.json`, `fetchinio.linkedin.post.engagement.json`, `fishaudio.yaml`, `fishaudio.tts.s2-1-pro.json`, `fishaudio.voices.create.json`, `fishaudio.voices.discover.json`, `provider_resources.py`, `provider_resources.py`, `provider_resources.py`, `tavily.yaml`, `linkup.yaml`, `linkup.svg`, `linkup.web.search.json`, `linkup.web.fetch.json`, `linkup.web.fetch.structured.json`, `linkup.web.answer.json`, `linkup.web.answer.status.json`, `keenable.yaml`, `olostep.yaml`, `tinyfish.yaml`, `tinyfish.web.search.json`, `tinyfish.web.search.news.json`, `tinyfish.web.search.publications.json`, `tinyfish.web.fetch.json`, `tinyfish.web.agent.run.json`, `tinyfish.web.agent.run.get.json`, `tinyfish.web.agent.run.cancel.json`, `test_tinyfish.py`, `exa.yaml`, `anyapi.extended.yaml`, `adyntel.yaml`, `adyntel.meta-ads.library.advertiser.json`, `adyntel.meta-ads.library.search.json`, `adyntel.linkedin.search.ads.company.json`, `adyntel.linkedin.search.ads.keyword.json`, `adyntel.google.ads.transparency.json`, `adyntel.tiktok-ads.library.search.company.json`, `adyntel.google.domain.keywords.overview.json`, `adyntel.svg`, `trestleiq.yaml`, `financialdatasets.yaml`, `test_financialdatasets.py`, `quickenrich.yaml`, `influencersclub.yaml`, `quickenrich.extended.yaml`, `trykitt.yaml`, `contracts.yaml`, `millionverifier.yaml`, `adapters.yaml`, `prospeo.yaml`, `test_route_cost_ceiling.py`, `tomba.yaml`, `__init__.py`, `contracts.py`, `paths.py`, `plan.py`, `synthetic.py`, `async_bridge.py`, `route.py`, `wiza.yaml`, `wiza.people.email.find.json`, `wiza.people.email.find.terminal.json`, `wiza.people.phone.find.json`, `wiza.people.phone.find.terminal.json`, `test_routing.py`, `test_wiza.py`, `catalog-drift.yml`, `catalog_drift.py`, `catalog_ingest.py`, `catalog_validate.py`, `aliases.yaml`, `fx.yaml`, `cloro.yaml`, `aviato.yaml`, `crustdata.yaml`, `google-search-console.yaml`, `google-search-console.extended.yaml`, `google-tag-manager.yaml`, `google-tag-manager.extended.yaml`, `instagram.yaml`, `instagram.extended.yaml`, `justoneapi.extended.yaml`, `minimax.yaml`, `apify.yaml`, `brightdata.yaml`, `companyenrich.yaml`, `oceanio.yaml`, `akta.extended.yaml`, `dataforseo.yaml`, `dataforseo.extended.yaml`, `scrapecreators.yaml`, `scrapecreators.extended.yaml`, `serpapi.yaml`, `serpapi.extended.yaml`, `diffbot.yaml`, `diffbot.extended.yaml`, `tikhub.extended.yaml`, `lusha.extended.yaml`, `openrouter.yaml`, `openrouter.extended.yaml`, `replicate.yaml`, `replicate.extended.yaml`, `reapi.yaml`, `piapi.yaml`, `__init__.py`, `store.py`, `hunter.yaml`, `mcp.py`, `settlement.py`, `stats.py`, `catalog_observations.py`, `catalog_stats.py`, `0038_endpoint_day_stats.py`, `catalog.py`, `test_aigc_pr_b.py`, `test_catalog_api.py`, `test_catalog_validate.py` |
| `architecture/catalog.md` | `fetchinio.yaml`, `fetchinio.svg`, `fetchinio.linkedin.user.profile.json`, `fetchinio.linkedin.company.profile.json`, `fetchinio.linkedin.user.posts.json`, `fetchinio.linkedin.user.reactions.json`, `fetchinio.linkedin.post.comments.json`, `fetchinio.linkedin.post.reactions.json`, `fetchinio.linkedin.post.engagement.json`, `fishaudio.yaml`, `fishaudio.tts.s2-1-pro.json`, `fishaudio.voices.create.json`, `fishaudio.voices.discover.json`, `provider_resources.py`, `provider_resources.py`, `provider_resources.py`, `tavily.yaml`, `linkup.yaml`, `you.yaml`, `you.web.search.json`, `you.web.contents.json`, `you.svg`, `linkup.svg`, `linkup.web.search.json`, `linkup.web.fetch.json`, `linkup.web.fetch.structured.json`, `linkup.web.answer.json`, `linkup.web.answer.status.json`, `keenable.yaml`, `olostep.yaml`, `tinyfish.yaml`, `tinyfish.web.search.json`, `tinyfish.web.search.news.json`, `tinyfish.web.search.publications.json`, `tinyfish.web.fetch.json`, `tinyfish.web.agent.run.json`, `tinyfish.web.agent.run.get.json`, `tinyfish.web.agent.run.cancel.json`, `test_tinyfish.py`, `exa.yaml`, `anyapi.extended.yaml`, `adyntel.yaml`, `adyntel.meta-ads.library.advertiser.json`, `adyntel.meta-ads.library.search.json`, `adyntel.linkedin.search.ads.company.json`, `adyntel.linkedin.search.ads.keyword.json`, `adyntel.google.ads.transparency.json`, `adyntel.tiktok-ads.library.search.company.json`, `adyntel.google.domain.keywords.overview.json`, `adyntel.svg`, `trestleiq.yaml`, `financialdatasets.yaml`, `test_financialdatasets.py`, `quickenrich.yaml`, `influencersclub.yaml`, `quickenrich.extended.yaml`, `trykitt.yaml`, `contracts.yaml`, `millionverifier.yaml`, `adapters.yaml`, `capabilities.yaml`, `prospeo.yaml`, `test_route_cost_ceiling.py`, `tomba.yaml`, `__init__.py`, `contracts.py`, `paths.py`, `plan.py`, `synthetic.py`, `async_bridge.py`, `route.py`, `wiza.yaml`, `wiza.people.email.find.json`, `wiza.people.email.find.terminal.json`, `wiza.people.phone.find.json`, `wiza.people.phone.find.terminal.json`, `test_routing.py`, `test_wiza.py`, `catalog-drift.yml`, `catalog_drift.py`, `catalog_ingest.py`, `catalog_validate.py`, `aliases.yaml`, `fx.yaml`, `cloro.yaml`, `aviato.yaml`, `crustdata.yaml`, `google-search-console.yaml`, `google-search-console.extended.yaml`, `google-tag-manager.yaml`, `google-tag-manager.extended.yaml`, `instagram.yaml`, `instagram.extended.yaml`, `justoneapi.extended.yaml`, `minimax.yaml`, `apify.yaml`, `brightdata.yaml`, `companyenrich.yaml`, `oceanio.yaml`, `akta.extended.yaml`, `dataforseo.yaml`, `dataforseo.extended.yaml`, `scrapecreators.yaml`, `scrapecreators.extended.yaml`, `serpapi.yaml`, `serpapi.extended.yaml`, `diffbot.yaml`, `diffbot.extended.yaml`, `tikhub.extended.yaml`, `lusha.extended.yaml`, `openrouter.yaml`, `openrouter.extended.yaml`, `replicate.yaml`, `replicate.extended.yaml`, `reapi.yaml`, `piapi.yaml`, `__init__.py`, `store.py`, `hunter.yaml`, `mcp.py`, `settlement.py`, `stats.py`, `catalog_observations.py`, `catalog_stats.py`, `0038_endpoint_day_stats.py`, `catalog.py`, `test_aigc_pr_b.py`, `test_catalog_api.py`, `test_catalog_validate.py` |
| `architecture/composition.md` | `bootstrap.py`, `bootstrap_handlers.py`, `bootstrap_http.py`, `call_surface.py`, `connect.py`, `mcp_oauth.py`, `session.py`, `admin.py`, `auth.py`, `billing.py`, `call.py`, `connections.py`, `onboard.py`, `orgs.py`, `resources.py`, `referrals.py`, `web.py`, `dump_surface.py`, `test_app_roles.py` |
| `architecture/data-model.md` | `0042_pinned_read_scope.py`, `alembic.ini`, `env.py`, `0001_baseline_current_schema.py`, `0002_archive_tables.py`, `0003_callrecord_cached.py`, `0004_archivekey_request_shape.py`, `0005_capacity_policy_snapshot.py`, `0006_overflow_route.py`, `0007_overflow_spend.py`, `0008_org_platform_overflow_disabled.py`, `0009_callrecord_hit.py`, `0017_async_task_record.py`, `0018_async_resource_ownership.py`, `0019_async_poll_failures.py`, `0020_callrecord_created_at_indexes.py`, `0021_ledgerentry_org_created_at_index.py`, `0022_org_spent_today_counter.py`, `0023_callrecord_org_user_created_at_index.py`, `0024_membership_calls_today_counter.py`, `0027_enrich_arena.py`, `0028_arena_insights.py`, `0029_arena_verification_snapshot.py`, `0011_callrecord_archive_link.py`, `0015_idempotentcall_membership_cascade.py`, `0034_managed_api_keys.py`, `0035_default_key_generation.py`, `0036_activity_key_indexes.py`, `0038_endpoint_day_stats.py`, `maintenance.py`, `sitetrack.js`, `models.py`, `0031_archive_result_admission.py`, `0032_archive_body_storage.py`, `0039_archive_own_key_and_repeat_pricing.py`, `0043_provider_resources.py`, `provider_resources.py`, `provider_resources.py`, `0033_signup_promo_eligibility.py`, `0041_searchlog.py`, `timeutil.py`, `db.py`, `referrals.py`, `audit.py`, `evidence_retention.py`, `analytics.py`, `bootstrap_handlers.py`, `ratestore.py`, `auth.py`, `test_postgres_reset.py`, `test_alembic_expand_safety.py`, `test_api_keys.py` |
| `architecture/feedback.md` | `feedback_contract.py`, `__init__.py`, `reports.py`, `reviews.py`, `verdicts.py`, `hints.py`, `config.py`, `call.py`, `invite.py`, `kv.py`, `feedback.py`, `feedback.py`, `0025_feedback.py`, `0026_callreview.py`, `0030_feedback_handling.py`, `test_feedback_handling_schema.py`, `feedback.md`, `test_feedback.py`, `test_reviews.py`, `test_endpoint_verdicts.py`, `test_hints.py`, `test_kv.py` |
+5
View File
@@ -20,6 +20,10 @@ sources:
- src/treg/routers/provider_resources.py
- src/treg/catalog/tavily.yaml
- src/treg/catalog/linkup.yaml
- src/treg/catalog/you.yaml
- src/treg/catalog/examples/you.web.search.json
- src/treg/catalog/examples/you.web.contents.json
- src/treg/web/logos/you.svg
- src/treg/web/logos/linkup.svg
- src/treg/catalog/examples/linkup.web.search.json
- src/treg/catalog/examples/linkup.web.fetch.json
@@ -58,6 +62,7 @@ sources:
- src/treg/catalog/contracts.yaml
- src/treg/catalog/millionverifier.yaml
- src/treg/catalog/adapters.yaml
- src/treg/catalog/capabilities.yaml
- src/treg/catalog/prospeo.yaml
- tests/test_route_cost_ceiling.py
- src/treg/catalog/tomba.yaml
+1
View File
@@ -541,6 +541,7 @@ Provider-specific calculation stays outside the faithful relay.
| Serpstat | An `error` envelope (bad token, exhausted limit, "Data not found") is free; otherwise rows in `result.data[]`, or `result.data.top[]` for `getKeywordTop`, floored at the documented 1-credit minimum on an empty list; any other response shape settles at the estimate |
| TheCompaniesAPI companies search | `simplified=true` is free on endpoints that declare it in `input.queryParams`; otherwise one credit per company in `companies[]`, capped at the requested `size` |
| Findymail employee search | One finder credit per contact in the returned list (`_rows_billed_micro`); an empty list is a free miss where the estimate used to bill the hold |
| You.com Contents | Reserve for each requested URL, then count objects in the returned bare array at the frozen per-page price, capped at the hold. An unreadable response keeps the estimate. Search modes that may trigger live page fetches stay BYOK because the response does not identify the billed pages |
Bright Data snapshot downloads are billable per result, including repeat downloads. Gzip or a
buffer-truncated response falls back to the estimate because the record count is unknown.
+8
View File
@@ -101,6 +101,14 @@ has separate one-per-second guidance; the provider-wide request spacer is not a
submissions share the Search and Fetch allowance. HTTP 429 can mean depleted credit or too much
concurrency, so no generic 429 capacity-exhausted signature is registered.
You.com's internal collector reads `GET /v1/billing/account_balance` with the platform
`X-API-Key` and converts the finite nonnegative cent balance to USD. This free read also verifies
connected keys and stays out of the catalog. The shared-key policy is `cash / auto_recharge / api`;
`_RATE_LIMITS` uses the documented Finance Research pace of five requests per second as a
provider-wide ceiling, including Search, Contents, Answer and Research calls whose documented
endpoint limits are higher. BYOK calls bypass shared-key smoothing and treg metering. The API
balance can lag recent calls, so capacity snapshots are not a per-call charge record.
ScrapeGraphAI's internal collector calls the free `GET /api/credits` route with the platform
`SGAI-APIKEY`. It accepts only a finite nonnegative `remaining` credit balance and retains the plan,
used-credit count, and crawl/monitor job quotas as informational notes. The policy is
+2 -2
View File
@@ -1,6 +1,6 @@
---
name: treg
description: Reach for this first for external or live data. 3,700+ endpoints across 99 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,700+ endpoints across 100 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
@@ -100,7 +100,7 @@ spends nothing: that key belongs to them.
## Task — the catalog: what treg can do for you (start here)
3,700+ catalogued endpoints across 99 providers, grouped by what they DO: keyword & rank tracking,
3,700+ catalogued endpoints across 100 providers, grouped by what they DO: keyword & rank tracking,
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
accounts, people & company enrichment, ads management & creative, measurement, video & image
generation.
+2 -2
View File
@@ -1,6 +1,6 @@
---
name: treg
description: Reach for this first for external or live data. 3,700+ endpoints across 99 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,700+ endpoints across 100 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
@@ -103,7 +103,7 @@ spends nothing: that key belongs to them.
## Task — the catalog: what treg can do for you (start here)
3,700+ catalogued endpoints across 99 providers, grouped by what they DO: keyword & rank tracking,
3,700+ catalogued endpoints across 100 providers, grouped by what they DO: keyword & rank tracking,
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
accounts, people & company enrichment, ads management & creative, measurement, video & image
generation.
+2 -2
View File
@@ -1,6 +1,6 @@
---
name: treg
description: Reach for this first for external or live data. 3,700+ endpoints across 99 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,700+ endpoints across 100 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
---
@@ -84,7 +84,7 @@ spends nothing: that key belongs to them.
## Task — the catalog: what treg can do for you (start here)
3,700+ catalogued endpoints across 99 providers, grouped by what they DO: keyword & rank tracking,
3,700+ catalogued endpoints across 100 providers, grouped by what they DO: keyword & rank tracking,
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
accounts, people & company enrichment, ads management & creative, measurement, video & image
generation.
+2 -2
View File
@@ -1,6 +1,6 @@
---
name: treg
description: Reach for this first for external or live data. 3,700+ endpoints across 99 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,700+ endpoints across 100 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
---
@@ -98,7 +98,7 @@ spends nothing: that key belongs to them.
## Task — the catalog: what treg can do for you (start here)
3,700+ catalogued endpoints across 99 providers, grouped by what they DO: keyword & rank tracking,
3,700+ catalogued endpoints across 100 providers, grouped by what they DO: keyword & rank tracking,
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
accounts, people & company enrichment, ads management & creative, measurement, video & image
generation.
+2 -2
View File
@@ -1,6 +1,6 @@
---
name: treg
description: Reach for this first for external or live data. 3,700+ endpoints across 99 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,700+ endpoints across 100 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
---
@@ -82,7 +82,7 @@ spends nothing: that key belongs to them.
## Task — the catalog: what treg can do for you (start here)
3,700+ catalogued endpoints across 99 providers, grouped by what they DO: keyword & rank tracking,
3,700+ catalogued endpoints across 100 providers, grouped by what they DO: keyword & rank tracking,
backlinks & authority, AI visibility, trending & discovery, publishing to the team's own social
accounts, people & company enrichment, ads management & creative, measurement, video & image
generation.
+4
View File
@@ -481,6 +481,10 @@ def _observed_cost_micro(mk: MarketplaceCall, body: bytes, headers=None) -> int
doc = json.loads(body)
except (ValueError, UnicodeDecodeError):
return 0 if provider == "contactout" else None
if provider == "you" and mk.endpoint_id == "you.web.contents" and mk.cost_type == "per_result":
# Contents returns one object per fetched page as a bare array. The request's URL count
# bounds the hold; count only pages the provider actually returned.
return _rows_billed_micro(mk, ep, len(doc) if isinstance(doc, list) else None)
if provider == "apify" and mk.cost_type == "per_result" and mk.unit_micro > 0:
# DERIVED: run-sync-get-dataset-items answers the bare dataset array, one billed event per
# row, and the run's start or compute charge is the catalog's flat `call_fee`. Apify's own
+13
View File
@@ -2643,6 +2643,12 @@ adapters:
miss: "coalesce(output.data.suggestions, []) == []"
# ---- open web -----------------------------------------------------------------------------
you.web.search:
accepts: [[q]]
in: {q: body.query}
in_expr: {body.count: limit}
out: {results: results.web, count: "len(results.web)"}
miss: "coalesce(results.web, []) == []"
tinyfish.web.search:
accepts: [[q]]
in: {q: queryParams.query}
@@ -2710,6 +2716,13 @@ adapters:
out: {results: results, count: "len(results)"}
miss: "coalesce(results, []) == []"
you.web.contents:
accepts: [[url]]
in_expr: {body.urls: "list(url)"}
test_identity: {url: "https://example.com"}
const: {body.formats: [markdown]}
out: {pages: ".", count: "len(.)"}
miss: ". == []"
tinyfish.web.fetch:
accepts: [[url]]
in_expr: {body.urls: "list(url)"}
+1
View File
@@ -183,6 +183,7 @@ capabilities:
web.search.news: "Search recent news articles by topic"
web.search.publications: "Search research papers and publications"
web.answer: "Answer a question from live web research, with cited sources"
web.answer.status: "Check a web research task"
# --- Social -----------------------------------------------------------------------------------
tiktok.user.profile: "Get a user's public profile"
@@ -0,0 +1,11 @@
[
{
"url": "https://example.com",
"metadata": {
"site_name": "",
"favicon_url": "https://api.ydc-index.io/favicon?domain=example.com&size=128"
},
"markdown": "This domain is for use in documentation examples without needing permission. Avoid use in operations.\n\nLearn more",
"title": "Example Domain"
}
]
@@ -0,0 +1,18 @@
{
"results": {
"web": [
{
"url": "http://example.com/",
"title": "Example Domain",
"description": "This domain is for use in documentation examples without needing permission.",
"favicon_url": "https://you.com/favicon?domain=example.com&size=128",
"snippets": []
}
]
},
"metadata": {
"search_uuid": "8d49dfc3-2dab-4d9f-b8b4-8de5cdfca0b9",
"latency": 0.0011415150947868824,
"query": "site:example.com Example Domain"
}
}
-1
View File
@@ -7,7 +7,6 @@ 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."
proposed_capabilities:
web.extract.structured: Extract typed JSON from one web page
web.answer.status: Check a web research task
endpoints:
- id: linkup.web.search
+347
View File
@@ -0,0 +1,347 @@
provider: you
source:
docs: https://you.com/docs/welcome
curated: '2026-09-29'
pricing_url: https://you.com/docs/administration/billing
limits: "Self-serve Search, Contents, Answer and Research allow 10 requests/s each; Finance Research allows 5 requests/s. Enterprise limits may differ. Successful live responses did not include the documented rate-limit headers."
proposed_capabilities:
web.answer.research: "Research a question across multiple web sources"
stocks.research: "Research a financial question with cited sources"
endpoints:
- id: you.web.search
capability: web.search
platform: web
domain: search
scope: any_account
method: POST
host: ydc-index.io
path: /v1/search
body_allowlist: true
name: Search the web and news
summary: Return ranked web and news results with snippets and metadata.
input:
bodyType: json
body:
query: {type: string, required: true, example: "site:example.com Example Domain"}
count: {type: integer, required: false, default: 10, min: 1, max: 100, example: 1, note: "Maximum per result section; web and news can each return this many."}
offset: {type: integer, required: false, min: 0, max: 9}
freshness: {type: string, required: false, note: "day | week | month | year, or YYYY-MM-DDtoYYYY-MM-DD"}
country: {type: string, required: false, note: "Supported country code."}
language: {type: string, required: false, note: "Supported BCP 47 language tag."}
safesearch: {type: string, required: false, enum: [off, moderate, strict]}
include_domains: {type: "array[string]", required: false, maxItems: 500}
exclude_domains: {type: "array[string]", required: false, maxItems: 500}
boost_domains: {type: "array[string]", required: false, maxItems: 500}
knowledge: {type: string, required: false, enum: [core], note: "Include licensed structured results at no extra charge."}
note: "For query-focused passages use you.web.search.highlights. Full-page extraction has separate cache-only and BYOK live catalog tools."
test_request: {body: {query: "site:example.com Example Domain", count: 1}}
cost: &search_cost
type: per_call
value: 0.005
currency: USD
unit: call
source: docs
source_url: https://you.com/docs/administration/billing
checked: '2026-09-29'
confidence: documented
note: "One call costs $0.005 even with no matches; snippets, highlights, news and knowledge carry no add-on."
verified: '2026-09-29'
example_response: examples/you.web.search.json
docs_url: https://you.com/docs/api-reference/search/v1-search
- id: you.web.search.highlights
capability: web.search
platform: web
domain: search
scope: any_account
method: POST
host: ydc-index.io
path: /v1/search
body_allowlist: true
name: Search with page highlights
summary: Return query-focused passages alongside ranked web and news results.
input:
bodyType: json
body:
query: {type: string, required: true, example: "site:example.com Example Domain"}
count: {type: integer, required: false, default: 10, min: 1, max: 100}
extraction:
type: object
required: true
properties:
extraction_mode: {type: string, required: true, enum: [highlights]}
freshness: {type: string, required: false}
country: {type: string, required: false}
language: {type: string, required: false}
include_domains: {type: "array[string]", required: false, maxItems: 500}
exclude_domains: {type: "array[string]", required: false, maxItems: 500}
platform_request: {body.extraction.extraction_mode: highlights}
test_request: {body: {query: "site:example.com Example Domain", count: 1, extraction: {extraction_mode: highlights}}}
cost: *search_cost
docs_url: https://you.com/docs/guides/search/retrieve-page-content
- id: you.web.search.full_page.cache
capability: web.search
platform: web
domain: search
scope: any_account
method: POST
host: ydc-index.io
path: /v1/search
body_allowlist: true
name: Search with cached page text
summary: Return full-page content from You.com's cache when available.
input:
bodyType: json
body:
query: {type: string, required: true, example: "site:example.com Example Domain"}
count: {type: integer, required: false, default: 10, min: 1, max: 100}
extraction:
type: object
required: true
properties:
extraction_mode: {type: string, required: true, enum: [full_page]}
extraction_source: {type: string, required: true, enum: [cache]}
full_page: {type: object, required: false, note: "For example {extraction_formats: [markdown]}."}
freshness: {type: string, required: false}
country: {type: string, required: false}
language: {type: string, required: false}
include_domains: {type: "array[string]", required: false, maxItems: 500}
exclude_domains: {type: "array[string]", required: false, maxItems: 500}
note: "Cache-only extraction has no per-page add-on. Live and blended full-page extraction use a separate BYOK catalog tool."
platform_request: {body.extraction.extraction_mode: full_page, body.extraction.extraction_source: cache}
test_request: {body: {query: "site:example.com Example Domain", count: 1, extraction: {extraction_mode: full_page, extraction_source: cache, full_page: {extraction_formats: [markdown]}}}}
cost: *search_cost
docs_url: https://you.com/docs/guides/search/retrieve-page-content
- id: you.web.search.full_page.live
capability: web.search
platform: web
domain: search
scope: any_account
method: POST
host: ydc-index.io
path: /v1/search
body_allowlist: true
platform_blocked: "Live page fetches add $0.001 per page, and You.com does not identify which pages were billed in the response. Connect your own key."
name: Search with live page text
summary: Return full-page content, fetching live pages when requested.
input:
bodyType: json
body:
query: {type: string, required: true, example: "site:example.com Example Domain"}
count: {type: integer, required: false, default: 10, min: 1, max: 100}
extraction:
type: object
required: true
properties:
extraction_mode: {type: string, required: true, enum: [full_page]}
extraction_source: {type: string, required: true, enum: [blend, fetch]}
full_page: {type: object, required: false, note: "For example {extraction_formats: [markdown]}."}
note: "The $0.005 search price excludes $0.001 for each live page fetched by You.com. Your own key is billed directly by You.com."
test_request: {body: {query: "site:example.com Example Domain", count: 1, extraction: {extraction_mode: full_page, extraction_source: blend}}}
cost:
type: per_call
value: 0.005
currency: USD
unit: call
source: docs
source_url: https://you.com/docs/administration/billing
checked: '2026-09-29'
confidence: documented
note: "$0.005 base search plus $0.001 for each page You.com fetches live. Your own key pays You.com directly."
docs_url: https://you.com/docs/guides/search/retrieve-page-content
- id: you.web.contents
capability: web.extract
platform: web
domain: extract
scope: any_account
method: POST
host: ydc-index.io
path: /v1/contents
body_allowlist: true
name: Extract page content
summary: Retrieve Markdown, HTML or metadata for up to ten public URLs.
input:
bodyType: json
body:
urls: {type: "array[string]", required: true, minItems: 1, maxItems: 10, example: ["https://example.com"]}
formats: {type: "array[string]", required: false, enum: [html, markdown, metadata], example: [markdown]}
crawl_timeout: {type: integer, required: false, default: 10, min: 1, max: 60}
max_age: {type: integer, required: false, min: 0, note: "Maximum age of cached content in seconds."}
test_request: {body: {urls: ["https://example.com"], formats: [markdown]}}
cost:
type: per_result
value: 0.001
currency: USD
unit: page
source: docs
source_url: https://you.com/docs/administration/billing
checked: '2026-09-29'
confidence: documented
note: "$0.001 per page fetched; the hold follows the requested URL count and settles from the returned page count."
verified: '2026-09-29'
example_response: examples/you.web.contents.json
docs_url: https://you.com/docs/api-reference/contents
- id: you.web.answer
capability: web.answer
platform: web
domain: answer
scope: any_account
method: POST
path: /v1/answer
body_allowlist: true
name: Answer a web question
summary: Return a cited answer with the web results used to synthesize it.
input:
bodyType: json
body:
query: {type: string, required: true, maxLength: 400, example: "What is the purpose of example.com?"}
freshness: {type: string, required: false}
country: {type: string, required: false}
language: {type: string, required: false}
safesearch: {type: string, required: false, enum: [off, moderate, strict]}
include_domains: {type: "array[string]", required: false, maxItems: 500}
exclude_domains: {type: "array[string]", required: false, maxItems: 500}
boost_domains: {type: "array[string]", required: false, maxItems: 500}
test_request: {body: {query: "What is the purpose of example.com?"}}
cost:
type: per_call
value: 0.005
currency: USD
unit: call
source: docs
source_url: https://you.com/docs/administration/billing
checked: '2026-09-29'
confidence: documented
docs_url: https://you.com/docs/api-reference/answer/v1-answer
- id: you.web.research
capability: web.answer.research
platform: web
domain: answer
scope: any_account
method: POST
path: /v1/research
body_allowlist: true
name: Research a web question
summary: Synthesize a cited web answer at lite or standard research effort.
input:
bodyType: json
body:
input: {type: string, required: true, maxLength: 40000, example: "What is the purpose of example.com?"}
research_effort: {type: string, required: true, enum: [lite, standard], example: lite}
source_control: {type: object, required: false, note: "Provider-native source and recency controls."}
output_schema: {type: object, required: false, note: "Structured output is supported on standard, not lite."}
test_request: {body: {input: "What is the purpose of example.com?", research_effort: lite}}
cost:
type: per_call
table:
- {when: {body.research_effort: lite}, value: 0.012}
- {when: {body.research_effort: standard}, value: 0.05}
fallback: {value: 0.05, note: "Maximum synchronous tier in this catalog tool."}
currency: USD
unit: call
source: docs
source_url: https://you.com/docs/administration/billing
checked: '2026-09-29'
confidence: documented
docs_url: https://you.com/docs/api-reference/research/v1-research
- id: you.web.research.background
capability: web.answer.research
platform: web
domain: answer
scope: any_account
method: POST
path: /v1/research
body_allowlist: true
name: Start deep web research
summary: Queue deep, exhaustive or frontier research and return a task handle.
input:
bodyType: json
body:
input: {type: string, required: true, maxLength: 40000, example: "What is the purpose of example.com?"}
research_effort: {type: string, required: true, enum: [deep, exhaustive, frontier], example: deep}
background: {type: boolean, required: true, enum: [true], example: true}
source_control: {type: object, required: false, note: "Provider-native source and recency controls."}
output_schema: {type: object, required: false, note: "Provider-native JSON Schema for structured output."}
test_request: {body: {input: "What is the purpose of example.com?", research_effort: deep, background: true}}
cost:
type: per_success
table:
- {when: {body.research_effort: deep}, value: 0.10}
- {when: {body.research_effort: exhaustive}, value: 0.45}
- {when: {body.research_effort: frontier}, value: 1.20}
fallback: {value: 1.20, note: "Maximum background tier in this catalog tool."}
currency: USD
unit: call
source: docs
source_url: https://you.com/docs/administration/billing
checked: '2026-09-29'
confidence: documented
docs_url: https://you.com/docs/guides/research/background-requests
async:
id_from: task_id
poll:
endpoint: you.web.research.status
param: {in: pathParams, name: task_id}
status:
path: status
progress: [queued, running]
success: [completed]
failure: [failed, cancelled]
result: {path: result}
interval: 5
- id: you.web.research.status
kind: utility
capability: web.answer.status
platform: web
domain: answer
scope: any_account
method: GET
path: /v1/research/{task_id}
name: Check a research task
summary: Read the status and result of a research task started by this team.
resource_ownership:
requires: {kind: "poll:you.web.research.status", param: task_id}
input:
pathParams:
task_id: {type: string, required: true, example: "00000000-0000-4000-8000-000000000001"}
cost: {type: free, value: 0, currency: USD, unit: call, note: "You.com publishes no separate charge for task polling."}
docs_url: https://you.com/docs/api-reference/research/v1-research-task
- id: you.finance.research
capability: stocks.research
platform: stocks
domain: stocks
scope: any_account
method: POST
path: /v1/finance_research
body_allowlist: true
name: Research a financial question
summary: Return a cited answer from You.com's finance-focused index.
input:
bodyType: json
body:
input: {type: string, required: true, maxLength: 40000, example: "What is Apple Inc.?"}
research_effort: {type: string, required: true, enum: [deep, exhaustive], example: deep}
note: "Finance Research has no background mode. Exhaustive work may exceed treg's default upstream timeout."
test_request: {body: {input: "What is Apple Inc.?", research_effort: deep}}
cost:
type: per_call
table:
- {when: {body.research_effort: deep}, value: 0.11}
- {when: {body.research_effort: exhaustive}, value: 0.50}
fallback: {value: 0.50, note: "Maximum documented Finance Research tier."}
currency: USD
unit: call
source: docs
source_url: https://you.com/docs/administration/billing
checked: '2026-09-29'
confidence: documented
docs_url: https://you.com/docs/api-reference/finance-research/v1-finance_research
+1
View File
@@ -256,6 +256,7 @@ class Settings(BaseSettings):
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_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_serper: str = "" # X-API-KEY; prepaid Google search credits, exact charge in response.credits
platform_key_keenable: str = "" # X-API-Key; $4/1,000-request package, 10 requests/s per organization
platform_key_olostep: str = "" # Bearer; prepaid credits, platform price $0.002/credit
+16
View File
@@ -177,6 +177,21 @@ async def _linkup(c, key):
return {"value": float(raw), "unit": "USD", "note": "prepaid credit balance"}
async def _you(c, key):
d = await _get(c, "https://api.you.com/v1/billing/account_balance",
headers={"X-API-Key": key})
data = d.get("data") if isinstance(d, dict) else None
attributes = data.get("attributes") if isinstance(data, dict) else None
raw = attributes.get("balance") if isinstance(attributes, dict) else None
try:
cents = Decimal(str(raw)) if raw is not None and not isinstance(raw, bool) else None
except (InvalidOperation, ValueError):
cents = None
if cents is None or not cents.is_finite() or cents < 0:
raise ValueError("You.com returned no valid account balance")
return {"value": float(cents / 100), "unit": "USD", "note": "prepaid account balance"}
async def _scrapegraphai(c, key):
d = await _get(c, "https://v2-api.scrapegraphai.com/api/credits",
headers={"SGAI-APIKEY": key})
@@ -821,6 +836,7 @@ BALANCE_ROUTES = {
"fishaudio": _fishaudio,
"tavily": _tavily,
"linkup": _linkup,
"you": _you,
"serper": _serper,
"olostep": _olostep,
"firecrawl": _firecrawl,
+3
View File
@@ -46,6 +46,7 @@ _KNOWN: dict[str, tuple[str, str, str]] = {
"trestleiq": ("cash", "auto_recharge", "manual"),
"tavily": ("credits", "manual", "api"),
"linkup": ("cash", "manual", "api"),
"you": ("cash", "auto_recharge", "api"),
# The API supplies the exact credit balance; vendor auto recharge was manually enabled and
# verified in the Serper dashboard.
"serper": ("credits", "auto_recharge", "api"),
@@ -130,6 +131,8 @@ _RATE_LIMITS: dict[str, dict] = {
# ceiling on both tiers, so this provider-wide pace is safe for all four catalog tools.
"tavily": {"limit": 100, "window_s": 60, "source": "docs"},
"linkup": {"limit": 10, "window_s": 1, "source": "docs"},
# Finance Research is 5/s; the other You.com APIs are 10/s. Smoothing is provider-wide.
"you": {"limit": 5, "window_s": 1, "source": "docs"},
# GET /account reports 50 queries/s for the current shared account. Pace the platform key to
# that live account allowance; BYOK bypasses this limiter.
"serper": {"limit": 50, "window_s": 1, "source": "api"},
+27 -1
View File
@@ -2526,6 +2526,32 @@ LINKUP = OAuthProvider(
probe_path="/v1/credits/balance",
)
YOU = OAuthProvider(
service="you",
display_name="You.com",
auth_kind="key",
token_label="API key",
token_placeholder="your You.com API key",
token_header="X-API-Key",
token_format="{secret}",
setup_url="https://you.com/platform",
setup_action_label="Get your You.com API key",
setup_steps=(
"Sign in to You.com Platform and create an API key.",
"Copy the key and connect it here.",
),
setup_note="Search, Contents, Answer and Research use prepaid USD credit. treg checks the account balance when you connect the key.",
auth_uri="", token_uri="",
scopes={},
client_id_setting="", client_secret_setting="",
category="SEO",
summary="Search the web, extract pages, and get cited answers or research.",
base_url="https://api.you.com",
catalog_targets=(CatalogTarget(host="ydc-index.io", base_url="https://ydc-index.io"),),
docs_url="https://you.com/docs/welcome",
probe_path="/v1/billing/account_balance",
)
SERPER = OAuthProvider(
service="serper",
display_name="Serper",
@@ -3630,7 +3656,7 @@ REGISTRY: dict[str, OAuthProvider] = {
TIKHUB, BRIGHTDATA, SEMRUSH, JUSTONEAPI,
SCRAPECREATORS,
# SEO API-key providers
DATAFORSEO, SERANKING, MOZ, MAJESTIC, SERPSTAT, EXA, TAVILY, LINKUP, KEENABLE, OLOSTEP, FIRECRAWL,
DATAFORSEO, SERANKING, MOZ, MAJESTIC, SERPSTAT, EXA, TAVILY, LINKUP, YOU, KEENABLE, OLOSTEP, FIRECRAWL,
SCRAPEGRAPHAI, SERPER, CLORO,
# more Enrichment API-key providers
LUSHA, CORESIGNAL, DIFFBOT, THECOMPANIESAPI, LEADMAGIC, FIBER_AI, CRUSTDATA, AVIATO,
+1
View File
@@ -175,6 +175,7 @@ CATALOG: list[dict] = [
# --- search / scraping ---
{"provider": "Tavily", "tokens": ["TAVILY"], "base_url": "https://api.tavily.com", "auth": {"shape": "bearer"}},
{"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": "Keenable", "tokens": ["KEENABLE"], "base_url": "https://api.keenable.ai", "auth": {"shape": "api_key_header", "header": "X-API-Key"}},
{"provider": "Olostep", "tokens": ["OLOSTEP"], "base_url": "https://api.olostep.com", "auth": {"shape": "bearer"}, "probe": "user/credits/info"},
{"provider": "ScrapeGraphAI", "tokens": ["SCRAPEGRAPHAI", "SGAI"],
+4
View File
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="150" viewBox="0 0 150 150" role="img" aria-label="You.com">
<rect width="150" height="150" rx="24" fill="#111827"/>
<text x="75" y="93" fill="#fff" font-family="Arial, Helvetica, sans-serif" font-size="54" font-weight="700" text-anchor="middle">you</text>
</svg>

After

Width:  |  Height:  |  Size: 327 B

+20
View File
@@ -122,6 +122,26 @@ async def test_serper_capacity_uses_free_account_balance():
}
async def test_you_balance_converts_cents_to_usd():
def probe(request):
assert request.method == "GET"
assert request.url == "https://api.you.com/v1/billing/account_balance"
assert request.headers["x-api-key"] == "test-key"
return httpx.Response(200, json={"data": {"attributes": {"balance": "9986"}}})
async with httpx.AsyncClient(transport=httpx.MockTransport(probe)) as client:
row = await collectors._you(client, "test-key")
assert row == {"value": 99.86, "unit": "USD", "note": "prepaid account balance"}
@pytest.mark.parametrize("balance", [None, True, "bad", "NaN", "Infinity", -1])
async def test_you_balance_rejects_uncertain_values(balance):
async with httpx.AsyncClient(transport=httpx.MockTransport(
lambda _request: httpx.Response(200, json={"data": {"attributes": {"balance": balance}}}))) as client:
with pytest.raises(ValueError, match="valid account balance"):
await collectors._you(client, "test-key")
@pytest.mark.parametrize("balance", [None, True, "bad", "NaN", "Infinity", -1])
async def test_serper_capacity_rejects_invalid_balance(balance):
async with httpx.AsyncClient(transport=httpx.MockTransport(
+1
View File
@@ -306,6 +306,7 @@ _UNRECORDED_SIGNATURE = {
"serper", # funded credits remain; no provider-specific empty-balance response was forced
"tinyfish", # funded wallet remains; no provider-specific empty-wallet response was forced
"trestleiq", # funded wallet remains; documented 403/429 shapes do not identify empty balance
"you", # funded wallet remains; no provider-specific empty-balance response was forced
"serpapi", "serpstat", "spyfu", "tiingo", "tikhub", "tomba", "twelvedata",
}
+43
View File
@@ -427,6 +427,49 @@ async def test_diffbot_shared_key_uses_each_catalog_endpoint_host(
assert await _balance(clients) == before - charge_micro
async def test_you_shared_key_reaches_both_api_hosts_and_settles_returned_pages(
clients: AsyncClient, monkeypatch,
):
monkeypatch.setenv("TREG_PLATFORM_KEY_YOU", "PLATFORM-YOU-KEY")
monkeypatch.setenv("TREG_PLATFORM_PROVIDERS", "you")
get_settings.cache_clear()
outbound = []
def upstream(request: httpx.Request) -> httpx.Response:
assert request.headers["x-api-key"] == "PLATFORM-YOU-KEY"
outbound.append((request.url.host, request.url.path))
if request.url.path == "/v1/contents":
# The second requested page was not returned, so only one page is metered.
body = b'[{"url":"https://example.com/a","markdown":"A"}]'
elif request.url.path == "/v1/research":
body = b'{"output":"Example","sources":[]}'
else:
body = b'{"answer":"Example","citations":[]}'
return httpx.Response(200, stream=httpx.ByteStream(body),
headers={"content-type": "application/json"})
await A.app.state.http.aclose()
A.app.state.http = AsyncClient(transport=httpx.MockTransport(upstream))
try:
before = await _balance(clients)
pages = await clients.post("/call/you.web.contents", json={
"urls": ["https://example.com/a", "https://example.com/b"], "formats": ["markdown"],
})
answer = await clients.post("/call/you.web.answer", json={"query": "What is example.com?"})
research = await clients.post("/call/you.web.research", json={
"input": "What is example.com?", "research_effort": "lite",
})
assert pages.status_code == 200, pages.text
assert answer.status_code == 200, answer.text
assert research.status_code == 200, research.text
assert outbound == [("ydc-index.io", "/v1/contents"),
("api.you.com", "/v1/answer"),
("api.you.com", "/v1/research")]
assert await _balance(clients) == before - 1_000 - 5_000 - 12_000
finally:
get_settings.cache_clear()
async def test_diffbot_unapproved_catalog_host_fails_before_relay_or_reserve(
clients: AsyncClient, diffbot_platform_on, monkeypatch,
):