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.
Related
- Module registry concept
- Feedback API — used by on-demand stubs to surface activation requests in the admin dashboard.