FR
Copied
API

Module registry API

Single source of truth listing every module the platform exposes — active scrapers, on-demand stubs, meta features, coming-soon items.

Module registry API

The Module registry is the single source of truth listing every module the platform exposes: active scrapers, on-demand stubs, meta features, and coming-soon items still gathering interest votes. The frontend reads the registry instead of hardcoding module slugs, so adding a module only takes two files (frontend/static/job_types.js and app/job_registry.py).

See also: /docs/concepts/module-registry.

Registry entry shape

Each module is described by a small object that the frontend renders in the dashboard tiles, the search palette, and the pricing pages.

Field Type Purpose
slug string Stable identifier. Used as job_type, route param, and registry key.
category string Group bucket (sources, enrich, signals, outreach, tools).
label object { "fr": "...", "en": "..." }. Bilingual display name.
needs string[] Upstream artifacts the module consumes (e.g. ["leads"]).
produces string[] Downstream artifacts it emits (e.g. ["emails"]).
pipelinable boolean Whether the module can be chained inside a Pipeline.
is_on_demand boolean Stub module — clicking activate opens a feedback thread, not a job.
coming_soon boolean Listed for interest voting only. No backend execution.
alpha_unavailable boolean Built and listed as active, but frozen during alpha. Its create endpoint returns 503.
api_endpoint string | null Path the dashboard calls to start a run, or null for stubs.

A module is at most one of is_on_demand, coming_soon, alpha_unavailable, or plain active. Active modules have a non-null api_endpoint; stubs and coming-soon modules have api_endpoint = null. An alpha_unavailable module is presented as active and keeps a non-null api_endpoint, but that endpoint returns 503 while the alpha freeze is in effect.


GET /api/modules-registry

Public endpoint. Returns the server-side mirror of the JS registry. The response is a flat object with one array per bucket plus a feature_pages mapping that points each active module to its published /features/<slug> sales page (or null if not written yet).

Response — 200 OK

{
  "active": [
    "ads_intelligence", "brand_assets", "dead_check", "delivery_check",
    "emails", "filter", "import", "legal_data", "legal_ids",
    "legal_mentions", "pagespeed", "phones_extra", "pricing", "reviews",
    "scrap", "socials", "sort", "techstack", "verify_emails",
    "viewport_test"
  ],
  "multi_proxy": [
    "dead_check", "emails", "legal_ids", "legal_mentions", "phones_extra",
    "pricing", "reviews", "scrap", "socials", "techstack"
  ],
  "parallel": [
    "ads_intelligence", "brand_assets", "delivery_check", "filter",
    "import", "legal_data", "pagespeed", "sort", "verify_emails",
    "viewport_test"
  ],
  "on_demand": [
    "email_campaign", "phone_carrier", "sms_campaign", "whatsapp_campaign"
  ],
  "meta": ["pipeline", "veille"],
  "coming_soon": [
    "ai_personalization", "ai_team_members", "bing_places", "campaign",
    "chrome_extension", "crm", "directories", "email_warmup",
    "funding", "hiring", "integrations", "job_changes", "linkedin",
    "mobile_phones", "multichannel", "natural_filter", "pagesjaunes",
    "press_monitoring", "public_api", "review_patterns", "seo_data",
    "tech_adoption", "tracking", "whatsapp", "yelp_tripadvisor"
  ],
  "alpha_unavailable": ["finance"],
  "feature_pages": {
    "scrap": "scraper-google-maps-gratuit-export-csv",
    "emails": "email-finder-pro-rgpd-france",
    "ads_intelligence": null
  }
}

The multi_proxy set lists scrapers that share the global VPN pool — only one can run at a time platform-wide. parallel modules use direct HTTP and may run concurrently. Clients that schedule jobs should check both sets to surface "Will queue" warnings.


GET /api/features

Returns the caller's interest state plus a global counter per coming-soon feature. The counts include every allowed feature id, even those with zero votes, so the frontend can render Needed (N) labels without a fallback branch.

The list of acceptable feature ids equals coming_soon from the registry, plus a tiny legacy set (company, monitoring, pagespeed) kept around to preserve historic votes.

Response — 200 OK

{
  "voted": ["linkedin", "funding"],
  "counts": {
    "linkedin": 27,
    "funding": 14,
    "hiring": 6,
    "ai_personalization": 3,
    "directories": 0,
    "press_monitoring": 0
  }
}

Specific cause: 401 caller is not authenticated.


POST /api/features/{feature_id}/interest

Records an interest vote for feature_id. The operation is idempotent — a second call by the same user is a no-op. Use DELETE on the same path to retract the vote.

feature_id is validated against the allow-list from the registry (coming-soon ids plus legacy ids). Unknown ids return 404 so the endpoint cannot be used as a write-anywhere KV store.

Request

POST /api/features/linkedin/interest

No body. The user is identified by session.

Response — 204 No Content

Empty body. Re-fetch GET /api/features for the updated counter.

Specific causes: 401 not authenticated; 403 authenticated but not active (pending invite); 404 feature_id does not match the registry allow-list.