Topolo Docs Topolo Platform
Open workspace

Search the public app catalogue

Search bounded public app candidates with exact ranking, complete response examples and clear saved-metadata versus viewer-access boundaries.

Outcome

Find bounded public app catalogue candidates using text search, with clear ranking, saved metadata and viewer-permission boundaries.

GET /api/catalog/search

Before you start

This published catalogue search is public, has no application permission and does not establish a user/organization entitlement. Reading a result is not app installation, assignment, launch authority, a working service check or access to its repository.

Native input is only optional q and integer limit1-40. There is no cursor, organization, permission, private-app, semantic/vector or inclusion override. Use the published schema rather than raw HTTP parsing tolerances.

All worked examples are complete source-derived synthetic UNRUN catalogue responses. No real app, private record, repository, entitlement, provider or business action was queried or executed; no application import/test/runtime probe was run.

Query and response

Action: app_topolo_developers.catalog.search.

HTTP200 is directly {query,topK,results}; there is no success/message/data wrapper, count or nextCursor in this handler. Default topK12, maximum40. query preserves trimmed input casing. Empty/whitespace q returns query:"" and empty results before catalogue/repository reads.

The first stage normalizes q with NFKC/lowercase, splits Unicode letters/numbers plus underscore/colon/hyphen into at most12 tokens and builds quoted prefix terms combined with AND. Empty tokenization yields no directory matches. The SQL uses FTS rank with public catalogue state and non-sunset runtime only; this does not prove actual runtime health or caller authorization.

Only up to topK FTS directory candidates are hydrated, with generation/directory/manifest identity coherence checks. Their repository URL values are read from current Developers control rows by app id. Hydration/lookup failure is not an empty-success certificate; the handler has no uniform structured catch envelope to invent.

The second stage maps each saved manifest to a store card and scores the original trimmed/lowercase literal query: exact slug/name3, slug/name prefix2, otherwise substring1 over id,slug,name,shortBlurb,description,marketplaceCategory; zero is removed. Ties sort by app name localeCompare, then results are capped topK. There is no embedding/model/vector call in this path.

Because FTS candidate selection happens before the different literal score, a multi-token/punctuation/Unicode-normalization query can yield fewer final matches or none despite token-level candidates. Results are bounded ranked candidates, not an exhaustive catalogue or universal relevance order; no continuation is exposed.

Store cards include canonical app identity/display text, localization keys, saved marketing/media, pricing and source metadata. Optional absent launch/icon/media/presentation keys are omitted. Saved repository URL is current control metadata, not fetched or permission-checked Git contents. Pricing/currency/status labels are saved presentation, not checkout availability, accepted budget or current financial authority.

The public cached projection deliberately returns entitlement:"unavailable",assigned:false,canLaunch:false and a request-access CTA because it has no requesting user. These are neutral unknown-per-viewer values, not a signed-in authorization denial. An authenticated client must apply current entitlement/seat overlay; server launch authorization remains separate.

launchable is an app-level capability based on saved web launch URL plus public/non-sunset state. It does not imply a live healthcheck, installed app or current caller canLaunch. Empty supportEmail/category/heroImage/screenshots and popularity0 can be source projection defaults, not a certification that underlying records lack these fields.

Worked requests and responses

An empty query returns immediately

Complete synthetic UNRUN HTTP200 for absent q and default limit; source returns before directory/hydration/repository reads. No catalogue or entitlement operation was executed.

Input:

{}

Response:

{
  "query": "",
  "topK": 12,
  "results": []
}

Use a relevant supported query; do not report an empty platform inventory.

An exact fictional app name matches

Complete synthetic UNRUN HTTP200 assuming FTS selects exactly this saved public/non-sunset third-party fixture manifest: appId/slug/name as shown, version1.0.0, business/organization tenancy, developer id shown, no marketing/commerce/web/native/icon/presentation extras, no saved repository URL and the shown publication time. All defaults/omitted optional fields follow that premise; no actual app or repository was queried.

Input:

{
  "q": "Fixture",
  "limit": 1
}

Response:

{
  "query": "Fixture",
  "topK": 1,
  "results": [
    {
      "id": "app_docs_fixture",
      "appId": "app_docs_fixture",
      "serviceSlug": "fixture",
      "slug": "fixture",
      "name": "Fixture",
      "nameKey": "platform.catalog.apps.fixture.name",
      "category": "",
      "marketplaceCategory": "community",
      "subcategory": null,
      "popularity": 0,
      "status": "active",
      "stageLabel": "Available",
      "surface": "Web",
      "shortBlurb": "",
      "shortBlurbKey": "platform.catalog.apps.fixture.shortBlurb",
      "taglineKey": "platform.catalog.apps.fixture.tagline",
      "description": "",
      "descriptionKey": "platform.catalog.apps.fixture.description",
      "docsUrl": "",
      "gallery": [],
      "benefits": [],
      "features": [],
      "stats": [],
      "gettingStarted": [],
      "worksWellWith": [],
      "version": "1.0.0",
      "pricingType": "free",
      "monthlyPrice": null,
      "currency": null,
      "priceLabel": null,
      "websiteUrl": "",
      "repoUrl": "",
      "supportEmail": "",
      "tags": [
        "community"
      ],
      "screenshots": [],
      "heroImage": "",
      "source": "community",
      "visibility": "public",
      "entitlement": "unavailable",
      "assigned": false,
      "canLaunch": false,
      "launchable": false,
      "launchBlockedReason": null,
      "cta": {
        "action": "request-access",
        "label": "Request access",
        "labelKey": "platform.catalog.cta.requestAccess"
      },
      "i18n": {
        "keyRoot": "platform.catalog.apps.fixture",
        "nameKey": "platform.catalog.apps.fixture.name",
        "shortBlurbKey": "platform.catalog.apps.fixture.shortBlurb",
        "taglineKey": "platform.catalog.apps.fixture.tagline",
        "descriptionKey": "platform.catalog.apps.fixture.description",
        "compatibility": {
          "topoloOneNameKey": "one.command.apps.fixture.name",
          "topoloOneSubtitleKey": "one.command.apps.fixture.subtitle"
        }
      },
      "settings": {
        "source": "topolo-developers-registry",
        "developerOwned": true,
        "i18n": {
          "keyRoot": "platform.catalog.apps.fixture",
          "nameKey": "platform.catalog.apps.fixture.name",
          "shortBlurbKey": "platform.catalog.apps.fixture.shortBlurb",
          "taglineKey": "platform.catalog.apps.fixture.tagline",
          "descriptionKey": "platform.catalog.apps.fixture.description",
          "compatibility": {
            "topoloOneNameKey": "one.command.apps.fixture.name",
            "topoloOneSubtitleKey": "one.command.apps.fixture.subtitle"
          }
        },
        "developerApp": {
          "appId": "app_docs_fixture",
          "slug": "fixture",
          "developerId": "dev_docs_fixture",
          "ownerType": "third_party",
          "audience": "business",
          "tenancy": "organization"
        }
      },
      "updatedAt": "2026-10-21T00:00:00.000Z",
      "score": 3
    }
  ]
}

Read score3 and canonical app id, keeping neutral viewer fields separate from authenticated access. Public visibility does not grant launch or Git access.

No candidate survives the query

Complete synthetic UNRUN HTTP200 assuming no candidate matches all FTS terms, or none survives literal second-stage score. It is not a promise of exhaustive semantic search.

Input:

{
  "q": "missing fixture definition",
  "limit": 5
}

Response:

{
  "query": "missing fixture definition",
  "topK": 5,
  "results": []
}

Refine a supported q; there is no hidden cursor or private-app override to invent.

Verify and recover

  1. Validate the direct response and canonical result app ids/slugs, literal score and saved publication facts. Preserve filters/topK and actual errors; do not invent a count, cursor or semantic-search guarantee.

  2. For a real task, discover the selected app action/resource and current authenticated entitlement/seat permissions separately. Public canLaunch:false is neutral projection, while app-level launchable is not caller authority or runtime-health proof.

  3. Use actual supported developer/owner repository and commercial workflows where needed. Saved repoUrl/pricing fields are not repository access, checkout approval, a deployed release or provider outcome.

  4. No inverse is needed for this search. On failed hydration/lookup, preserve the real status/error and source query rather than reporting empty success or probing private apps.

Change log

  • 2026-10-21: Added direct search response, FTS/literal ranking stages, complete store-card example and neutral viewer/launch/pricing/repository boundaries with synthetic unrun carriers.