Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: looot Catalog API
version: 0.1.0
description: Discover, inspect, run, and pay for real (or fixture) provider operations through one bearer token.
servers:
- url: https://api.looot.ai
description: Public API (default)
- url: https://coset-gateway.onrender.com
description: Legacy host -- still live, for tokens issued before the public domain existed
- url: http://127.0.0.1:8787
description: Local development
security:
- bearerAuth: []
tags:
- name: Catalog
paths:
/v1/catalog/endpoints:
get:
summary: Paged, filtered, faceted catalog listing
parameters:
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 5000
- name: cursor
in: query
schema:
type: string
maxLength: 4096
- name: category
in: query
schema:
type: string
- name: platform
in: query
schema:
type: string
- name: provider
in: query
schema:
type: string
- name: capability
in: query
schema:
type: string
- name: keyless
in: query
schema:
type: boolean
- name: verified
in: query
schema:
type: boolean
- name: maxPriceMicros
in: query
schema:
type: integer
minimum: 0
- name: hidden
in: query
schema:
type: boolean
- name: facets
in: query
schema:
type: boolean
responses:
'200':
description: Catalog listing page with nextCursor and, when facets=true, category/platform/provider/capability counts for the filtered set
'304':
description: Catalog unchanged since If-None-Match
'403':
description: catalog:read scope required
tags:
- Catalog
operationId: getV1CatalogEndpoints
x-operation-id-source: derived
/v1/catalog/search:
get:
summary: Ranked full-text catalog search, with capability expansion and a stemmed-token…
description: 'The same search core answers MCP `search` (10 title rows by default) and MCP search_catalog (50 full rows by default, like this route). A title row is a subset of this route''s row: endpointId, provider, name, capability, category, estimatedPrice, priceBasis, access, executionMode, costPerSuccessUsd (facts.costPerSuccessUsd), async (facts.async), works, sourceCapability and credential, in the same order for the same q, limit and offset for a customer token. A platform operator token differs: this route always includes unavailable rows, while MCP honors an explicit filters.includeUnavailable false.'
parameters:
- name: q
in: query
required: true
schema:
type: string
minLength: 1
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 200
- name: offset
in: query
description: Where the page starts in the ranked list; pass the previous page's nextOffset (null on the last page).
schema:
type: integer
minimum: 0
- name: category
in: query
schema:
type: string
- name: platform
in: query
schema:
type: string
- name: provider
in: query
schema:
type: string
- name: capability
in: query
schema:
type: string
- name: keyless
in: query
schema:
type: boolean
- name: verified
in: query
schema:
type: boolean
- name: mock
in: query
description: true/false excludes the other kind; omitted keeps both but real providers still rank above mocks
schema:
type: boolean
- name: maxPriceMicros
in: query
schema:
type: integer
minimum: 0
- name: hidden
in: query
schema:
type: boolean
- name: prefer
in: query
description: 'How providers are ordered inside a job: balanced (default), cheapest, reliable or fastest. Any other value is a 400 validation_error. Every item''s facts carry it and the body echoes it; it changes the order only once the gateway serves the shared ranking.'
schema:
type: string
enum:
- cheapest
- reliable
- fastest
- balanced
responses:
'200':
description: 'Ranked catalog items (each carrying mock, verified, keyless, runnableNow, stats, access, matchedBy, facts, works, credential and sourceCapability; capability is the resolved job id), same shape as the listing, plus the prefer value used. An empty page may carry warnings (no_supply_for_job) or priceHint (price_above_max: maxPriceMicros removed every endpoint that does the named job; it names the cheapest)'
'400':
description: q is required
'403':
description: catalog:read scope required
tags:
- Catalog
operationId: getV1CatalogSearch
x-operation-id-source: derived
/v1/catalog/overview:
get:
security: []
summary: 'What the catalog covers: categories > platforms > jobs with provider, endpoint…'
description: 'Publicly readable without a bearer token; the same answer for every caller, rebuilt only when the catalog revision (or a platform key or fee) changes. Counts the rows the live public catalog lists (GET /v1/public-catalog when it serves the live catalog): the same row rules and public record checks (hidden slugs, prohibited, mock, unpriced, inactive and disabled rows, and records the public schema refuses, are left out). A category is the vocabulary category of the job''s platform, `other` when the platform is not in the vocabulary. Every level (category, platform, job) carries providerCount (distinct providers), endpointCount, runnableCount (runnable without your own key: keyless, or a platform key exists), cheapestPerCall and cheapestPerResult (lowest prices, the price you pay, null when nothing is priced that way; never compared with each other). The default answer is depth summary (totals plus one entry per category, a few KB); depth=full is the whole document (about 490 KB). category or platform narrows to one branch (default depth platforms; depth=jobs lists its jobs) and then answers filter instead of totals. topic answers the matching jobs, at most 25. Each view has its own ETag; revalidate with If-None-Match.'
parameters:
- name: depth
in: query
required: false
schema:
enum:
- summary
- platforms
- jobs
- full
description: 'summary (default): totals and per category counts. platforms: adds each category''s platforms. jobs: adds each platform''s jobs (a tree). full: each category''s platforms[] and flat jobs[] with job.platform. Default platforms when category or platform is given; pass jobs to list the branch jobs. Not allowed with topic.'
- name: category
in: query
required: false
schema:
type: string
maxLength: 200
description: 'A category id: answers only that category. Unknown: 404 unknown_category.'
- name: platform
in: query
required: false
schema:
type: string
maxLength: 200
description: 'A platform id: answers the category holding it with only that platform. Unknown (or not in the given category): 404 unknown_platform.'
- name: topic
in: query
required: false
schema:
type: string
maxLength: 200
description: 'Words such as email or phone: answers the jobs whose id, title, platform or category match (the job-first search matcher), best first, at most 25, with truncated. Combines with category and platform.'
- name: If-None-Match
in: header
required: false
schema:
type: string
responses:
'200':
description: 'Catalog overview view: a depth view, or a topic view when topic is given'
headers:
ETag:
schema:
type: string
description: W/"rev-<revision>-<digest of this view>"
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/CatalogOverview'
- $ref: '#/components/schemas/CatalogOverviewTopic'
'304':
description: View unchanged since If-None-Match
'400':
description: 'validation_error: error.field names the argument (depth, category, platform or topic) and error.message says what to send'
'404':
description: unknown_category (error.categories lists the ids) or unknown_platform; error.field names the argument
'503':
description: 'catalog_loading: no catalog snapshot is loaded yet; retry after retry-after seconds. production_runtime_unavailable: this deployment serves no v2 catalog'
tags:
- Catalog
operationId: getV1CatalogOverview
x-operation-id-source: derived
/v1/catalog/overlay:
get:
summary: Per-workspace catalog overlay (connected, platformSupply) by provider
description: Per-workspace overlay (connected, platformSupply) for each provider, returned in one call.
responses:
'200':
description: '{ generatedAt, workspaceId, providers: { [providerId]: { connected, platformSupply } } }'
'403':
description: catalog:read scope required
tags:
- Catalog
operationId: getV1CatalogOverlay
x-operation-id-source: derived
/v1/catalog/endpoints/{endpointId}/verify:
post:
summary: Run an endpoint's stored testRequest and stamp verifiedAt on success
description: Dispatches through the exact same execute/settle path POST /v1/runs uses, then on success only stamps verifiedAt/verifiedRunId. Requires both runs:execute and provider-registry:write.
responses:
'200':
description: '{ ok, endpointId, version, runId, latencyMs, error }'
'403':
description: runs:execute and provider-registry:write scopes both required
'404':
description: Endpoint not found
'409':
description: Endpoint has no stored testRequest to verify against
tags:
- Catalog
operationId: postV1CatalogEndpointsByEndpointIdVerify
x-operation-id-source: derived
components:
schemas:
CatalogOverview:
type: object
additionalProperties: false
required:
- revision
- builtAt
- depth
- categories
properties:
revision:
type: string
builtAt:
type: string
format: date-time
depth:
enum:
- summary
- platforms
- jobs
- full
filter:
type: object
additionalProperties: false
description: Present only on a narrowed view (category or platform given); such a view has no totals
properties:
category:
type: string
platform:
type: string
totals:
type: object
additionalProperties: false
description: Whole catalog; only on a view that is not narrowed
required:
- categories
- platforms
- jobs
- providers
- endpoints
- runnableEndpoints
properties:
categories:
type: integer
platforms:
type: integer
jobs:
type: integer
providers:
type: integer
endpoints:
type: integer
runnableEndpoints:
type: integer
categories:
type: array
items:
type: object
additionalProperties: false
required:
- id
- title
- platformCount
- jobCount
- providerCount
- endpointCount
- runnableCount
- cheapestPerCall
- cheapestPerResult
properties:
id:
type: string
title:
type: string
platformCount:
type: integer
jobCount:
type: integer
providerCount:
type: integer
description: Distinct providers with at least one listed endpoint at this level
endpointCount:
type: integer
runnableCount:
type: integer
description: Endpoints runnable without your own key (keyless, or a platform key exists)
cheapestPerCall:
type:
- number
- 'null'
description: Lowest per-call price in dollars at this level (the price you pay); null when nothing is priced per call
cheapestPerResult:
type:
- number
- 'null'
description: Lowest per-result price in dollars at this level (the price you pay); null when nothing is priced per result
platforms:
type: array
description: Depth platforms, jobs and full, and any view narrowed by platform
items:
type: object
additionalProperties: false
required:
- id
- title
- jobCount
- providerCount
- endpointCount
- runnableCount
- cheapestPerCall
- cheapestPerResult
properties:
id:
type: string
title:
type: string
jobCount:
type: integer
providerCount:
type: integer
description: Distinct providers with at least one listed endpoint at this level
endpointCount:
type: integer
runnableCount:
type: integer
description: Endpoints runnable without your own key (keyless, or a platform key exists)
cheapestPerCall:
type:
- number
- 'null'
description: Lowest per-call price in dollars at this level (the price you pay); null when nothing is priced per call
cheapestPerResult:
type:
- number
- 'null'
description: Lowest per-result price in dollars at this level (the price you pay); null when nothing is priced per result
jobs:
type: array
description: 'Depth jobs only: this platform''s jobs'
items:
type: object
additionalProperties: false
required:
- id
- title
- providerCount
- endpointCount
- runnableCount
- cheapestPerCall
- cheapestPerResult
properties:
id:
type: string
title:
type: string
providerCount:
type: integer
description: Distinct providers with at least one listed endpoint at this level
endpointCount:
type: integer
runnableCount:
type: integer
description: Endpoints runnable without your own key (keyless, or a platform key exists)
cheapestPerCall:
type:
- number
- 'null'
description: Lowest per-call price in dollars at this level (the price you pay); null when nothing is priced per call
cheapestPerResult:
type:
- number
- 'null'
description: Lowest per-result price in dollars at this level (the price you pay); null when nothing is priced per result
jobs:
type: array
description: 'Depth full only: the category''s jobs, each naming its platform'
items:
type: object
additionalProperties: false
required:
- id
- title
- platform
- providerCount
- endpointCount
- runnableCount
- cheapestPerCall
- cheapestPerResult
properties:
id:
type: string
title:
type: string
platform:
type: string
providerCount:
type: integer
description: Distinct providers with at least one listed endpoint at this level
endpointCount:
type: integer
runnableCount:
type: integer
description: Endpoints runnable without your own key (keyless, or a platform key exists)
cheapestPerCall:
type:
- number
- 'null'
description: Lowest per-call price in dollars at this level (the price you pay); null when nothing is priced per call
cheapestPerResult:
type:
- number
- 'null'
description: Lowest per-result price in dollars at this level (the price you pay); null when nothing is priced per result
CatalogOverviewTopic:
type: object
additionalProperties: false
required:
- revision
- builtAt
- topic
- matchCount
- truncated
- jobs
properties:
revision:
type: string
builtAt:
type: string
format: date-time
topic:
type: string
description: 'The topic as matched: lowercased, punctuation folded to spaces'
filter:
type: object
additionalProperties: false
description: Present only on a narrowed view (category or platform given); such a view has no totals
properties:
category:
type: string
platform:
type: string
matchCount:
type: integer
description: Jobs that match before the cap
truncated:
type: boolean
description: True when matchCount is over the 25 jobs answered
jobs:
type: array
maxItems: 25
items:
type: object
additionalProperties: false
required:
- id
- title
- providerCount
- endpointCount
- runnableCount
- cheapestPerCall
- cheapestPerResult
- category
- platform
properties:
id:
type: string
title:
type: string
providerCount:
type: integer
description: Distinct providers with at least one listed endpoint at this level
endpointCount:
type: integer
runnableCount:
type: integer
description: Endpoints runnable without your own key (keyless, or a platform key exists)
cheapestPerCall:
type:
- number
- 'null'
description: Lowest per-call price in dollars at this level (the price you pay); null when nothing is priced per call
cheapestPerResult:
type:
- number
- 'null'
description: Lowest per-result price in dollars at this level (the price you pay); null when nothing is priced per result
category:
type: string
platform:
type: string
securitySchemes:
bearerAuth:
type: http
scheme: bearer