Skip to main content

Marketplace

  • Sells as: the marketplace 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.

Shared product-tier addon-marketplace / venture-storefront engine (Track L convergence). Catalog CRUD + install/uninstall + reviews/ratings + payment-verification + submit/approve/reject workflow, so no product re-rolls the marketplace plumbing. I5 capability-face only (Stripe checkout for a paid addon stays product-side; core records/verifies the resulting payment). I4 own Postgres store. I6 org-scoped: every row carries organization_id; every route resolves the tenant via the shared tenancy primitive. Business outcomes (including a {error} payload) return HTTP 200 so a converging product's thin client is a 1:1 passthrough; non-200 is reserved for tenancy (401/403/422) + store-unavailable (503).

  • Group: Commerce & revenue
  • Contract: contracts/marketplace/v1/openapi.yaml
  • Console: Manage the marketplace product in the console →
  • Runbook: operational checklist for marketplaceinternal (Vagary Labs ops; not part of this public site): docs/runbooks/capability-operations.md#marketplace
  • 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/marketplace/items
  • Capability face (internal first-party — NOT customer-keyed):
    • https://api.vagarylabs.com/v1/connectors
    • https://api.vagarylabs.com/v1/developers
    • https://api.vagarylabs.com/v1/items
    • https://api.vagarylabs.com/v1/stats
    • https://api.vagarylabs.com/v1/users

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)

MethodPathMetricScope
POST/product/v1/marketplace/itemsmarketplace_operationswrite

Capability face (internal first-party — NOT customer-keyed)

  • /v1/connectors
  • /v1/developers
  • /v1/items
  • /v1/stats
  • /v1/users

Endpoints

MethodPathSummary
GET/v1/itemsList catalog items (filtered by status/category/addon_type)
POST/v1/itemsSubmit an addon (→ pending_review)
GET/v1/items/searchSearch published items by name/description
GET/v1/items/&#123;item_id&#125;Get one item
PUT/v1/items/&#123;item_id&#125;Developer updates own item (allow-listed fields)
DELETE/v1/items/&#123;item_id&#125;Developer soft-deletes (unpublish) own item
POST/v1/items/&#123;item_id&#125;/approveAdmin publishes a pending item
POST/v1/items/&#123;item_id&#125;/rejectAdmin rejects a pending item
POST/v1/items/&#123;item_id&#125;/installInstall an item (payment-gated for paid items → 200 {error: Payment required} when unpaid)
DELETE/v1/items/&#123;item_id&#125;/installUninstall an item
GET/v1/items/&#123;item_id&#125;/reviewsList reviews for an item
POST/v1/items/&#123;item_id&#125;/reviewsAdd a review (must have installed; one per user/item)
POST/v1/items/&#123;item_id&#125;/paymentsRecord a completed payment (product ran Stripe checkout — I5)
GET/v1/items/&#123;item_id&#125;/payments/verifyIs there a completed payment for (user,item)?
GET/v1/items/&#123;item_id&#125;/statsOne item's install/rating stats
GET/v1/users/&#123;user_id&#125;/installedA user's installed items
GET/v1/developers/&#123;developer_id&#125;/itemsA developer's items (any status)
GET/v1/statsAggregate marketplace stats (admin)
GET/v1/connectorsList the org's registered connectors (Row10d — connector-adapter registry)
POST/v1/connectorsRegister a connector (auth-config + typed actions) → published 'integration' item; body is the ConnectorSpec (optionally under spec)
POST/v1/connectors/toolsBuild the dialog-core tool bundle for a user's INSTALLED connectors — body {user_id, credentials?}; returns {tools, tool_dispatch, unresolved} (credentials rendered into headers only, never persisted)
POST/v1/connectors/reference/&#123;key&#125;Register a built-in reference connector (key: http
GET/v1/connectors/catalogBrowse the ready-to-register connector catalog (~25 popular SaaS APIs; auth SCHEMES + typed action summaries only — no secret)
POST/v1/connectors/catalog/seedBulk-seed catalog connectors into the org as addon_type='integration' items — body {keys?[], category?, base_urls?{}, developer_id?}; requires_base_url vendors without a base_url are skipped
POST/v1/connectors/catalog/&#123;key&#125;Register ONE catalog connector → published 'integration' item — body {base_url?, name?, developer_id?}; base_url REQUIRED for a requires_base_url vendor (your instance/store/subdomain host)
GET/v1/connectors/&#123;item_id&#125;Get one connector's stored spec (auth SCHEME only — never a secret value)
GET/healthLiveness (open, tailnet-scoped)
GET/metricsPrometheus metrics (open, tailnet-scoped)

Schemas

Error

FieldTypeDescription
errorstring

Item

FieldTypeDescription
item_idstring
developer_idstring
namestring
descriptionstring
addon_typestring
categorystring
tagsarray
pricenumber
pricing_modelstring
versionstring
statusstring
rating_avgnumber
rating_countinteger
install_countinteger
created_atnumber
updated_atnumber

Generated by scripts/gen-capability-docs.py from contracts/marketplace/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.