- Sells as: the
vertical-factory product (a product-scoped API key). This capability has no separate product-face contract — its public product route reuses the capability contract below; see the Edge route table's Product face row.
Vertical-factory capability — the generic engine that registers, spins up and lifecycles a content vertical from a VerticalDefinition, and runs domain-pack DETECTION + field EXTRACTION over content. Extracted from vagary-platform's vertical registry + domain-pack machinery so any content product can provision verticals over one shared engine instead of re-implementing the registry/detect/extract plumbing. The DURABLE registry (VerticalDefinitions) is core-owned (Postgres, I4). Domain-PACKS (the per-vertical extraction IP) stay product-local and are supplied as INPUT to detect/extract — never persisted here. The org-tier company-creator (Paperclip) is a different tier and is untouched (I2).
- Group: Content & media
- Contract:
contracts/vertical-factory/v1/openapi.yaml
- Console: Manage the
vertical-factory product in the console →
- Runbook: operational checklist for
vertical-factory — internal (Vagary Labs ops; not part of this public site): docs/runbooks/capability-operations.md#vertical-factory
- Public base:
https://api.vagarylabs.com (the consolidated API gateway — one host, per-brand sibling api.<zone>)
- Auth: a product API key (
vgk_…) issued from the console — Authorization: Bearer vgk_…
- Product face (customer-keyed):
https://api.vagarylabs.com/product/v1/verticals
Edge route table
The routes this capability actually serves on the public edge — live-synced from GET https://api.vagarylabs.com/product/v1/_meta/catalog (snapshot v1). The metric is the request-granularity billing counter; the scope is the key permission required.
Product face (customer-keyed)
| Method | Path | Metric | Scope |
|---|
POST | /product/v1/verticals | vertical_operations | write |
Endpoints
| Method | Path | Summary |
|---|
POST | /v1/vertical-factory/verticals | Register (upsert) a VerticalDefinition — spin up / lifecycle a content vertical |
GET | /v1/vertical-factory/verticals | List registered VerticalDefinitions (org-scoped) |
GET | /v1/vertical-factory/verticals/{vertical_id} | Get a VerticalDefinition (or 404) |
PATCH | /v1/vertical-factory/verticals/{vertical_id} | Partially update a VerticalDefinition (builtins reject id/is_builtin changes) |
DELETE | /v1/vertical-factory/verticals/{vertical_id} | Delete a VerticalDefinition (builtins cannot be deleted → 409) |
GET | /v1/vertical-factory/verticals/{vertical_id}/collection | Resolve the storage collection name for a vertical (falls back to news_articles) |
POST | /v1/vertical-factory/packs | Register a DomainPack into the EPHEMERAL org-scoped in-memory cache (NON-DURABLE, per-replica, cleared on restart). Convenience so /detect + /extract can be called by vertical_id without re-shipping the pack. The pack is NEVER written to Postgres — its durable home stays in the product. |
| | |
GET | /v1/vertical-factory/packs | List vertical_ids currently in the ephemeral in-memory pack cache (org-scoped) |
POST | /v1/vertical-factory/detect | Detect which verticals are relevant for content. Packs are supplied INLINE in packs (canonical, stateless) or, if packs is omitted, the org's ephemeral in-memory cache is used. Zero persistence. |
| | |
POST | /v1/vertical-factory/extract | Extract vertical-specific fields from content using a DomainPack's regex FieldSpecs + generic format validators. The pack is supplied INLINE in pack, or resolved by vertical_id from the ephemeral in-memory cache. Zero persistence. |
| | |
GET | /health | Liveness + role + store state |
GET | /metrics | Prometheus exposition (BFT fail-open) |
Schemas
VerticalDefinition
The canonical vertical-lifecycle definition (converged from the platform's rich, Mongo-persisted VerticalDefinition). Identity + storage + discovery + enrichment + scoring + addons + UI. This is the ONLY object the core store persists. domain_pack is an OPTIONAL back-reference to the pack's identity — the engine treats pack CONTENT as opaque and never persists it (see DomainPack).
| Field | Type | Description |
|---|
vertical_id | string | |
display_name | string | |
description | string | |
collection_name | string | storage collection; defaults to <vertical_id>s |
content_schema | object | required/optional field-name lists (storage schema hints — NOT extraction regex) |
discovery_strategies | array | |
enrichment_pipeline | array | ordered enrichment step names; extraction is one such step, run over the vertical's DomainPack (data, not owned here) |
scoring_weights | object | |
addon_ids | array | |
ui_config | object | |
is_builtin | boolean | |
enabled | boolean | |
created_at | number | |
updated_at | number | |
ScoringWeights
| Field | Type | Description |
|---|
freshness | number | |
relevance | number | |
quality | number | |
engagement | number | |
source_trust | number | |
UIConfig
| Field | Type | Description |
|---|
card_layout | string | |
detail_layout | string | |
primary_color | string | |
icon | string | |
show_sentiment | boolean | |
show_trending | boolean | |
addon_slots | array | |
DomainPack
The per-vertical extraction IP (the platform's VerticalConfig, subsumed here as a sibling of the definition and back-referenced by vertical_id). Supplied as INPUT to /detect + /extract, or cached ephemerally in RAM. NEVER persisted by core — its durable home stays in the product (I5).
| Field | Type | Description |
|---|
vertical_id | string | |
display_name | string | |
description | string | |
extraction_fields | array | |
category_keywords | array | |
relevance_terms | array | |
min_relevance_terms | integer | |
VerticalFieldSpec
| Field | Type | Description |
|---|
name | string | |
pattern | string | regex used for extraction |
required | boolean | |
validator | string | name of a generic format validator (numeric_amount |
| Field | Type | Description |
|---|
vertical_id | string | |
extracted_fields | object | |
relevance_score | number | |
validation_errors | array | |
matched_keywords | array | |
is_relevant | boolean | |
VerticalRef
| Field | Type | Description |
|---|
vertical_id | string | |
display_name | string | |
Error
| Field | Type | Description |
|---|
error | string | |
Generated by scripts/gen-capability-docs.py from contracts/vertical-factory/v1/openapi.yaml — the contract IS the source of truth; edit the contract, not this page. The Edge route table section is synced from the live edge catalog snapshot (v1) — re-sync with python3 scripts/sync-edge-catalog.py.