{"openapi":"3.1.0","info":{"title":"OngoingAI API","version":"1.0.0-draft","description":"The ecommerce data layer: who sells online, on what platform, with which technology stack, observed continuously with provenance. Every fact on this API comes from a completed observation and carries the dates that support it. Incomplete observations are never negative evidence.","contact":{"name":"OngoingAI","url":"https://ongoingai.dev","email":"api@ongoing.ai"},"termsOfService":"https://ongoing.ai/terms"},"servers":[{"url":"https://api.ongoing.ai","description":"Production"}],"security":[{"ApiKey":[]}],"tags":[{"name":"Account","description":"Key validation, plan limits, and usage."},{"name":"Stores","description":"Store profiles from completed observations."},{"name":"Technologies","description":"The canonical technology vocabulary."},{"name":"Service","description":"Health and the live OpenAPI document."}],"components":{"securitySchemes":{"ApiKey":{"type":"http","scheme":"bearer","bearerFormat":"oai_live_… or oai_test_…","description":"Workspace API key as a bearer token. Create keys in the dashboard under Settings → API keys. Test keys (`oai_test_`) answer from a fixed test tenant and never queue production scans."}},"schemas":{"Health":{"type":"object","properties":{"ok":{"type":"boolean","description":"Whether the service can answer requests.","example":true},"service":{"type":"string","enum":["ongoingai-api"],"description":"Service name.","example":"ongoingai-api"},"version":{"type":"string","description":"API contract version.","example":"v1"},"build":{"type":["string","null"],"description":"Git sha of the running build, or `null` locally.","example":"3ee36e2b"},"registry_checksum":{"type":["string","null"],"description":"Checksum of the fingerprint registry in this build. Changes when detection rules change.","example":"sha256:9f2c…"}},"required":["ok","service","version","build","registry_checksum"]},"ApiIndex":{"type":"object","properties":{"name":{"type":"string","description":"Service name.","example":"OngoingAI API"},"description":{"type":"string","description":"One line on what the API serves.","example":"Ecommerce store, technology, product, and change intelligence."},"documentation_url":{"type":"string","format":"uri","description":"Developer documentation.","example":"https://ongoingai.dev"},"rest":{"type":"object","properties":{"base_url":{"type":"string","format":"uri","description":"Prefix for every REST path.","example":"https://api.ongoing.ai/v1"},"version":{"type":"string","description":"Contract version served here.","example":"v1"},"openapi_url":{"type":"string","format":"uri","description":"The OpenAPI document this build serves, which is the authoritative description of every operation.","example":"https://api.ongoing.ai/v1/openapi.json"},"authentication":{"type":"object","properties":{"scheme":{"type":"string","enum":["bearer"],"description":"Every authenticated request carries an API key as a bearer token.","example":"bearer"},"header":{"type":"string","description":"The header to send.","example":"Authorization: Bearer oai_live_…"},"keys_url":{"type":"string","format":"uri","description":"Where a signed-in user creates and revokes keys.","example":"https://app.ongoing.ai/dashboard/settings/api-keys"}},"required":["scheme","header","keys_url"],"description":"How to authenticate."}},"required":["base_url","version","openapi_url","authentication"],"description":"The REST interface, and the only one a workspace API key authenticates."},"graphql":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"GraphQL endpoint.","example":"https://api.ongoing.ai/graphql"},"access":{"type":"string","description":"Who may call it. Stated plainly because a workspace API key does NOT authenticate GraphQL: it takes a service token issued directly to a first-party surface. Partner integrations use REST.","example":"First-party service tokens issued by OngoingAI. Workspace API keys do not authenticate this endpoint."}},"required":["url","access"],"description":"The GraphQL interface, used by our own surfaces."}},"required":["name","description","documentation_url","rest","graphql"],"description":"What this host serves and where to go next."},"VersionIndex":{"type":"object","properties":{"version":{"type":"string","description":"Contract version.","example":"v1"},"documentation_url":{"type":"string","format":"uri","description":"Developer documentation.","example":"https://ongoingai.dev"},"openapi_url":{"type":"string","format":"uri","description":"The OpenAPI document for this version.","example":"https://api.ongoing.ai/v1/openapi.json"},"endpoints":{"type":"object","additionalProperties":{"type":"string"},"description":"Operation id to URL, with `{}` marking a path parameter. Only operations this build actually serves are listed, so an endpoint absent here is not available yet. The OpenAPI document describes them in full.","example":{"getAccount":"https://api.ongoing.ai/v1/account","getStore":"https://api.ongoing.ai/v1/stores/{domain}"}},"authentication":{"type":"object","properties":{"scheme":{"type":"string","enum":["bearer"],"description":"Every authenticated request carries an API key as a bearer token.","example":"bearer"},"header":{"type":"string","description":"The header to send.","example":"Authorization: Bearer oai_live_…"},"keys_url":{"type":"string","format":"uri","description":"Where a signed-in user creates and revokes keys.","example":"https://app.ongoing.ai/dashboard/settings/api-keys"}},"required":["scheme","header","keys_url"],"description":"How to authenticate."}},"required":["version","documentation_url","openapi_url","endpoints","authentication"],"description":"The operations served at this version."},"Account":{"type":"object","properties":{"workspace":{"type":"object","properties":{"id":{"type":"string","description":"Workspace id.","example":"ws_01J9X4K6ZP3M8Q2R5T7V9W1Y3A"},"name":{"type":"string","description":"Workspace name.","example":"Acme Agency"}},"required":["id","name"],"description":"The workspace that owns the key."},"key":{"type":"object","properties":{"id":{"type":"string","description":"Key id.","example":"key_01J9X4K6ZP3M8Q2R5T7V9W1Y3A"},"label":{"type":"string","description":"Label chosen at creation.","example":"Clay production"},"prefix":{"type":"string","description":"Key tag plus the first four characters of the secret. Safe to log, and how a key is identified in the dashboard.","example":"oai_live_a1b2"},"environment":{"type":"string","enum":["live","test"],"description":"`test` keys answer from the fixed test tenant and never queue production scans.","example":"live"},"scopes":{"type":"array","items":{"$ref":"#/components/schemas/Scope"},"description":"Scopes granted to this key."},"expires_at":{"type":["string","null"],"format":"date-time","description":"Expiry, or `null` for none.","example":null}},"required":["id","label","prefix","environment","scopes","expires_at"],"description":"The key used for this request."},"plan":{"type":"object","properties":{"slug":{"$ref":"#/components/schemas/PlanSlug"},"limits":{"$ref":"#/components/schemas/PlanLimits"}},"required":["slug","limits"],"description":"The workspace plan as enforced right now."},"period":{"$ref":"#/components/schemas/Period"}},"required":["workspace","key","plan","period"],"example":{"workspace":{"id":"ws_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","name":"Acme Agency"},"key":{"id":"key_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","label":"Clay production","prefix":"oai_live_a1b2","environment":"live","scopes":["read:stores","read:signals"],"expires_at":null},"plan":{"slug":"growth","limits":{"rpm":300,"concurrency":10,"enrich_batch_max":100,"freshness_days":30,"history_days":365,"live_refreshes_per_period":500}},"period":{"starts_at":"2026-09-01T00:00:00Z","ends_at":"2026-10-01T00:00:00Z","included":{"lookup_cached":10000,"lookup_live":500,"history_query":10000,"refresh_requested":0},"used":{"lookup_cached":1234,"lookup_live":7,"history_query":88,"refresh_requested":0}}}},"Scope":{"type":"string","enum":["read:stores","read:signals","read:watchlists","write:watchlists","write:scans","read:webhooks","write:webhooks","read:jobs","admin:workspace"],"description":"Permission attached to an API key. A request to an operation outside the key scopes returns `403 forbidden_scope`."},"PlanSlug":{"type":"string","enum":["free","pro","growth","partner"]},"PlanLimits":{"type":"object","properties":{"rpm":{"type":"integer","exclusiveMinimum":0,"description":"Requests per minute for this key.","example":120},"concurrency":{"type":"integer","exclusiveMinimum":0,"description":"Simultaneous in-flight requests for this key.","example":5},"enrich_batch_max":{"type":"integer","exclusiveMinimum":0,"description":"Maximum domains per `POST /v1/stores/enrich`.","example":100},"freshness_days":{"type":"integer","exclusiveMinimum":0,"description":"Observations older than this are returned as `stale`.","example":30},"history_days":{"type":"integer","exclusiveMinimum":0,"description":"Maximum lookback for history and signal search.","example":365},"live_refreshes_per_period":{"type":"integer","minimum":0,"description":"Scans that `refresh: true` may queue per billing period.","example":100}},"required":["rpm","concurrency","enrich_batch_max","freshness_days","history_days","live_refreshes_per_period"]},"Period":{"type":"object","properties":{"starts_at":{"type":"string","format":"date-time","description":"Start of the current billing period.","example":"2026-09-01T00:00:00Z"},"ends_at":{"type":"string","format":"date-time","description":"End of the current billing period; counters reset here.","example":"2026-10-01T00:00:00Z"},"included":{"type":"object","properties":{"lookup_cached":{"type":"integer","minimum":0,"description":"Units for this billing unit.","example":1234},"lookup_live":{"type":"integer","minimum":0,"description":"Units for this billing unit.","example":1234},"history_query":{"type":"integer","minimum":0,"description":"Units for this billing unit.","example":1234},"refresh_requested":{"type":"integer","minimum":0,"description":"Units for this billing unit.","example":1234}},"description":"Units included in the plan for this period, keyed by billing unit.","example":{"lookup_cached":10000,"lookup_live":100,"history_query":10000,"refresh_requested":0}},"used":{"type":"object","properties":{"lookup_cached":{"type":"integer","minimum":0,"description":"Units for this billing unit.","example":1234},"lookup_live":{"type":"integer","minimum":0,"description":"Units for this billing unit.","example":1234},"history_query":{"type":"integer","minimum":0,"description":"Units for this billing unit.","example":1234},"refresh_requested":{"type":"integer","minimum":0,"description":"Units for this billing unit.","example":1234}},"description":"Units consumed so far by all keys in the workspace, keyed by billing unit.","example":{"lookup_cached":1234,"lookup_live":7,"history_query":88,"refresh_requested":0}}},"required":["starts_at","ends_at","included","used"]},"ErrorEnvelope":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","unauthorized","forbidden_scope","not_found","rate_limited","conflict","payment_required","not_implemented","internal"],"description":"Stable machine-readable code. Branch on this, never on `message`. The HTTP status always matches: 400 invalid_request, 401 unauthorized, 403 forbidden_scope, 404 not_found, 429 rate_limited, 409 conflict, 402 payment_required, 501 not_implemented, 500 internal.","example":"unauthorized"},"message":{"type":"string","description":"Human-readable explanation. Wording may change between releases.","example":"Missing or invalid API key."},"request_id":{"type":"string","description":"Identifier for this request, also sent as the `X-Request-Id` response header. Quote it when contacting support.","example":"req_01J9X4K6ZP3M8Q2R5T7V9W1Y3A"}},"required":["code","message","request_id"],"description":"The error."}},"required":["error"],"description":"Every non-2xx response has this shape."},"Usage":{"type":"object","properties":{"period":{"$ref":"#/components/schemas/Period"},"by_key":{"type":"array","items":{"type":"object","properties":{"key_id":{"type":"string","description":"Key id.","example":"key_01J9X4K6ZP3M8Q2R5T7V9W1Y3A"},"label":{"type":"string","description":"Key label.","example":"Clay production"},"used":{"type":"object","properties":{"lookup_cached":{"type":"integer","minimum":0,"description":"Units for this billing unit.","example":1234},"lookup_live":{"type":"integer","minimum":0,"description":"Units for this billing unit.","example":1234},"history_query":{"type":"integer","minimum":0,"description":"Units for this billing unit.","example":1234},"refresh_requested":{"type":"integer","minimum":0,"description":"Units for this billing unit.","example":1234}},"description":"Units consumed by this key, keyed by billing unit.","example":{"lookup_cached":900,"lookup_live":2,"history_query":10,"refresh_requested":0}}},"required":["key_id","label","used"]},"description":"Consumption per key in the workspace, including revoked keys with usage this period."}},"required":["period","by_key"]},"StoreResponse":{"type":"object","properties":{"match":{"type":"string","enum":["matched","stale"],"description":"`stale` when the last completed observation is older than the plan freshness window.","example":"matched"},"store":{"$ref":"#/components/schemas/Store"}},"required":["match","store"],"example":{"match":"matched","store":{"domain":"gymshark.com","storefront_host":"www.gymshark.com","storefront_id":"sf_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","brand_group_id":"bg_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","name":"Gymshark","platform":{"slug":"shopify","name":"Shopify","confidence":"high","first_observed_at":"2025-11-02T09:41:00Z","last_confirmed_at":"2026-09-08T04:12:31Z"},"status":{"state":"active_storefront","as_of":"2026-09-08T04:12:31Z"},"technologies":[{"slug":"klaviyo","name":"Klaviyo","category":"email-marketing","install_state":"active","confidence":"high","first_observed_at":"2026-02-14T11:05:12Z","last_confirmed_at":"2026-09-08T04:12:31Z"},{"slug":"gorgias","name":"Gorgias","category":"customer-support","install_state":"active","confidence":"high","first_observed_at":"2026-08-30T03:58:10Z","last_confirmed_at":"2026-09-08T04:12:31Z"},{"slug":"yotpo","name":"Yotpo","category":"reviews","install_state":"configured","confidence":"medium","first_observed_at":"2026-01-20T08:00:00Z","last_confirmed_at":"2026-09-08T04:12:31Z"}],"geography":{"country":"GB","basis":"observed"},"industry":{"slug":"apparel","basis":"classified"},"catalog":{"product_count":1284,"available_count":null,"currency":"GBP","price_range":{"p25":28,"median":34,"p75":98},"as_of":"2026-09-09T02:20:00Z","coverage":"first_page"},"observation":{"last_completed_scan_at":"2026-09-08T04:12:31Z","scope":"full","coverage_note":null},"recent_signals":[{"id":"evt_7Q2M4K9ZP3R5T7V9W1Y3A6B8C","type":"technology_added","technology":"gorgias","from":null,"to":null,"effective_at":"2026-08-30T03:58:10Z","confirmed_at":"2026-09-01T04:02:44Z","confidence":"high"}],"profile_url":"https://ongoing.ai/stores/gymshark.com"}}},"Store":{"type":"object","properties":{"domain":{"type":"string","description":"Canonical registrable domain. The stable identity for this store across the API.","example":"gymshark.com"},"storefront_host":{"type":"string","description":"Host that serves the storefront, which may be a subdomain of `domain`.","example":"www.gymshark.com"},"storefront_id":{"type":"string","description":"Opaque stable id for this storefront; survives domain changes within a brand group.","example":"sf_01J9X4K6ZP3M8Q2R5T7V9W1Y3A"},"brand_group_id":{"type":["string","null"],"description":"Id shared by regional storefronts of one brand, or `null` when no group is known.","example":"bg_01J9X4K6ZP3M8Q2R5T7V9W1Y3A"},"name":{"type":["string","null"],"description":"Store name as displayed on the storefront.","example":"Gymshark"},"platform":{"anyOf":[{"$ref":"#/components/schemas/Platform"},{"type":"null"}],"description":"Detected commerce platform, or `null` if none was confirmed."},"status":{"type":"object","properties":{"state":{"$ref":"#/components/schemas/StoreStatus"},"as_of":{"type":"string","format":"date-time","description":"When the state was last confirmed.","example":"2026-09-08T04:12:31Z"}},"required":["state","as_of"],"description":"Lifecycle state and its confirmation time."},"technologies":{"type":"array","items":{"$ref":"#/components/schemas/StoreTechnology"},"description":"Technologies with their install state and observation dates. An empty list on a `homepage_only` or `partial` observation means \"not seen\", not \"none installed\"."},"geography":{"$ref":"#/components/schemas/Geography"},"industry":{"$ref":"#/components/schemas/Industry"},"catalog":{"anyOf":[{"$ref":"#/components/schemas/CatalogSummary"},{"type":"null"}],"description":"Catalog aggregates, or `null` before the first census."},"observation":{"$ref":"#/components/schemas/Observation"},"recent_signals":{"type":"array","items":{"$ref":"#/components/schemas/RecentSignal"},"maxItems":5,"description":"Up to five most recent confirmed signals. Full history is on `/v1/stores/{domain}/history`."},"profile_url":{"type":"string","format":"uri","description":"Public OngoingAI page for this store.","example":"https://ongoing.ai/stores/gymshark.com"}},"required":["domain","storefront_host","storefront_id","brand_group_id","name","platform","status","technologies","geography","industry","catalog","observation","recent_signals","profile_url"],"description":"A store profile assembled only from completed observations.","example":{"domain":"gymshark.com","storefront_host":"www.gymshark.com","storefront_id":"sf_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","brand_group_id":"bg_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","name":"Gymshark","platform":{"slug":"shopify","name":"Shopify","confidence":"high","first_observed_at":"2025-11-02T09:41:00Z","last_confirmed_at":"2026-09-08T04:12:31Z"},"status":{"state":"active_storefront","as_of":"2026-09-08T04:12:31Z"},"technologies":[{"slug":"klaviyo","name":"Klaviyo","category":"email-marketing","install_state":"active","confidence":"high","first_observed_at":"2026-02-14T11:05:12Z","last_confirmed_at":"2026-09-08T04:12:31Z"},{"slug":"gorgias","name":"Gorgias","category":"customer-support","install_state":"active","confidence":"high","first_observed_at":"2026-08-30T03:58:10Z","last_confirmed_at":"2026-09-08T04:12:31Z"},{"slug":"yotpo","name":"Yotpo","category":"reviews","install_state":"configured","confidence":"medium","first_observed_at":"2026-01-20T08:00:00Z","last_confirmed_at":"2026-09-08T04:12:31Z"}],"geography":{"country":"GB","basis":"observed"},"industry":{"slug":"apparel","basis":"classified"},"catalog":{"product_count":1284,"available_count":null,"currency":"GBP","price_range":{"p25":28,"median":34,"p75":98},"as_of":"2026-09-09T02:20:00Z","coverage":"first_page"},"observation":{"last_completed_scan_at":"2026-09-08T04:12:31Z","scope":"full","coverage_note":null},"recent_signals":[{"id":"evt_7Q2M4K9ZP3R5T7V9W1Y3A6B8C","type":"technology_added","technology":"gorgias","from":null,"to":null,"effective_at":"2026-08-30T03:58:10Z","confirmed_at":"2026-09-01T04:02:44Z","confidence":"high"}],"profile_url":"https://ongoing.ai/stores/gymshark.com"}},"Platform":{"type":"object","properties":{"slug":{"type":"string","description":"Platform technology slug.","example":"shopify"},"name":{"type":"string","description":"Display name.","example":"Shopify"},"confidence":{"$ref":"#/components/schemas/Confidence"},"first_observed_at":{"type":"string","format":"date-time","description":"First completed observation with this platform.","example":"2025-11-02T09:41:00Z"},"last_confirmed_at":{"type":"string","format":"date-time","description":"Most recent completed observation with this platform.","example":"2026-09-08T04:12:31Z"}},"required":["slug","name","confidence","first_observed_at","last_confirmed_at"]},"Confidence":{"type":"string","enum":["high","medium","low"],"description":"How strongly the completed observation supports the fact. `high` is corroborated by more than one independent signal; `low` rests on a single weak signal and should be treated as a hint."},"StoreStatus":{"type":"string","enum":["candidate","reachable","verified_ecommerce","active_storefront","inactive"],"description":"Lifecycle state derived only from completed observations. `inactive` requires confirmation across two completed scans; a blocked or failed fetch never moves a store here."},"StoreTechnology":{"type":"object","properties":{"slug":{"type":"string","description":"Technology slug.","example":"klaviyo"},"name":{"type":"string","description":"Display name.","example":"Klaviyo"},"category":{"type":"string","description":"Category slug.","example":"email-marketing"},"install_state":{"$ref":"#/components/schemas/InstallState"},"confidence":{"$ref":"#/components/schemas/Confidence"},"first_observed_at":{"type":"string","format":"date-time","description":"First completed observation where this technology was present.","example":"2026-02-14T11:05:12Z"},"last_confirmed_at":{"type":"string","format":"date-time","description":"Most recent completed observation where it was present.","example":"2026-09-08T04:12:31Z"}},"required":["slug","name","category","install_state","confidence","first_observed_at","last_confirmed_at"]},"InstallState":{"type":"string","enum":["active","configured","inactive"],"description":"`active` means the technology was loading on the storefront in the last completed observation. `configured` means it is referenced but not loading (for example a disabled app block). `inactive` means a prior completed observation saw it active and a later completed observation of the same scope did not. Absence from the list is not `inactive`; see `observation.scope`."},"Geography":{"type":"object","properties":{"country":{"type":["string","null"],"minLength":2,"maxLength":2,"description":"ISO 3166-1 alpha-2 country code, or `null` when not determined.","example":"GB"},"basis":{"type":["string","null"],"enum":["observed","inferred",null],"description":"`observed` comes from storefront settings or shipping origin seen in a completed scan; `inferred` comes from currency, language, and hosting signals.","example":"observed"}},"required":["country","basis"]},"Industry":{"type":"object","properties":{"slug":{"type":["string","null"],"description":"Industry slug, or `null` when unclassified.","example":"apparel"},"basis":{"type":["string","null"],"enum":["classified","declared",null],"description":"`classified` is our catalog-based classification; `declared` comes from the store itself.","example":"classified"}},"required":["slug","basis"]},"CatalogSummary":{"type":"object","properties":{"product_count":{"type":"integer","minimum":0,"description":"Products seen in the last completed catalog census.","example":1284},"available_count":{"type":["integer","null"],"minimum":0,"description":"Of those, products with at least one purchasable variant. `null` when the census recorded counts but not availability, which is the case for catalogs observed before availability was published.","example":null},"currency":{"type":["string","null"],"minLength":3,"maxLength":3,"description":"ISO 4217 currency the catalog was observed in.","example":"GBP"},"price_range":{"type":["object","null"],"properties":{"p25":{"type":"number","minimum":0,"description":"25th percentile price.","example":28},"median":{"type":"number","minimum":0,"description":"Median price.","example":34},"p75":{"type":"number","minimum":0,"description":"75th percentile price.","example":98}},"required":["p25","median","p75"],"description":"Price distribution in `currency`, or `null` when the observation did not pass the statistics gate. Percentiles rather than minimum and maximum: a single mispriced sample moves an extreme but not a quartile."},"as_of":{"type":"string","format":"date-time","description":"When the catalog census completed.","example":"2026-09-09T02:20:00Z"},"coverage":{"type":"string","enum":["full","first_page","partial"],"description":"How much of the catalog the census read. `first_page` is the default depth; counts under it are lower bounds.","example":"first_page"}},"required":["product_count","available_count","currency","price_range","as_of","coverage"],"description":"Aggregates from the product catalog census. Never per-product data on this endpoint."},"Observation":{"type":"object","properties":{"last_completed_scan_at":{"type":["string","null"],"format":"date-time","description":"When the most recent scan of this store completed successfully. `null` means the store is known but has never been fully observed; treat every other field as unknown rather than absent.","example":"2026-09-08T04:12:31Z"},"scope":{"anyOf":[{"$ref":"#/components/schemas/ObservationScope"},{"type":"null"}],"description":"Coverage of that completed scan, or `null` when there has been none."},"coverage_note":{"type":["string","null"],"description":"Plain-language caveat about what the observation could and could not see, for example a bot challenge on product pages.","example":"Product pages returned a bot challenge; storefront and homepage were observed."}},"required":["last_completed_scan_at","scope","coverage_note"],"description":"Provenance of the facts on a store object. Incomplete observations are never negative evidence: nothing in the API infers an uninstall, closure, or migration from a scan that did not complete."},"ObservationScope":{"type":"string","enum":["full","partial","homepage_only"],"description":"What the last completed scan covered. Read absence against this: a technology missing from a `homepage_only` observation may still be installed on other pages. A failed or blocked fetch never produces an observation at all, so it never appears here."},"RecentSignal":{"type":"object","properties":{"id":{"type":"string","description":"Deterministic event id. The same fact has the same id on every delivery and replay; dedupe on it.","example":"evt_7Q2M4K9ZP3R5T7V9W1Y3A6B8C"},"type":{"$ref":"#/components/schemas/SignalType"},"technology":{"type":["string","null"],"description":"Technology slug for technology events; `null` otherwise.","example":"gorgias"},"from":{"type":["string","null"],"description":"Previous platform slug for `platform_migrated`; `null` otherwise.","example":null},"to":{"type":["string","null"],"description":"New platform slug for `platform_migrated`; `null` otherwise.","example":null},"effective_at":{"type":"string","format":"date-time","description":"Best estimate of when the change happened: the first completed observation showing the new state.","example":"2026-08-30T03:58:10Z"},"confirmed_at":{"type":"string","format":"date-time","description":"When the confirmation rule was satisfied and the event became deliverable.","example":"2026-09-01T04:02:44Z"},"confidence":{"$ref":"#/components/schemas/Confidence"}},"required":["id","type","technology","from","to","effective_at","confirmed_at","confidence"]},"SignalType":{"type":"string","enum":["store_first_observed","technology_added","technology_removed","platform_migrated","store_became_active","store_became_inactive"],"description":"The public signal vocabulary. Removal, migration, and inactivity require confirmation across completed observations; an addition needs one completed scan showing presence and a prior completed scan of comparable scope showing absence."},"EnrichResponse":{"type":"object","properties":{"request_id":{"type":"string","description":"Same value as the `X-Request-Id` header.","example":"req_01J9X4K6ZP3M8Q2R5T7V9W1Y3A"},"results":{"type":"array","items":{"$ref":"#/components/schemas/EnrichResult"},"description":"One result per input, in input order."},"billed":{"type":"object","properties":{"lookup_cached":{"type":"integer","minimum":0,"description":"Units billed for matched and stale results.","example":2},"lookup_live":{"type":"integer","minimum":0,"description":"Units billed for queued scans.","example":0}},"required":["lookup_cached","lookup_live"],"description":"What this request consumed."}},"required":["request_id","results","billed"],"example":{"request_id":"req_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","results":[{"input":"gymshark.com","match":"matched","reason":null,"store":{"domain":"gymshark.com","storefront_host":"www.gymshark.com","storefront_id":"sf_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","brand_group_id":"bg_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","name":"Gymshark","platform":{"slug":"shopify","name":"Shopify","confidence":"high","first_observed_at":"2025-11-02T09:41:00Z","last_confirmed_at":"2026-09-08T04:12:31Z"},"status":{"state":"active_storefront","as_of":"2026-09-08T04:12:31Z"},"technologies":[{"slug":"klaviyo","name":"Klaviyo","category":"email-marketing","install_state":"active","confidence":"high","first_observed_at":"2026-02-14T11:05:12Z","last_confirmed_at":"2026-09-08T04:12:31Z"},{"slug":"gorgias","name":"Gorgias","category":"customer-support","install_state":"active","confidence":"high","first_observed_at":"2026-08-30T03:58:10Z","last_confirmed_at":"2026-09-08T04:12:31Z"},{"slug":"yotpo","name":"Yotpo","category":"reviews","install_state":"configured","confidence":"medium","first_observed_at":"2026-01-20T08:00:00Z","last_confirmed_at":"2026-09-08T04:12:31Z"}],"geography":{"country":"GB","basis":"observed"},"industry":{"slug":"apparel","basis":"classified"},"catalog":{"product_count":1284,"available_count":null,"currency":"GBP","price_range":{"p25":28,"median":34,"p75":98},"as_of":"2026-09-09T02:20:00Z","coverage":"first_page"},"observation":{"last_completed_scan_at":"2026-09-08T04:12:31Z","scope":"full","coverage_note":null},"recent_signals":[{"id":"evt_7Q2M4K9ZP3R5T7V9W1Y3A6B8C","type":"technology_added","technology":"gorgias","from":null,"to":null,"effective_at":"2026-08-30T03:58:10Z","confirmed_at":"2026-09-01T04:02:44Z","confidence":"high"}],"profile_url":"https://ongoing.ai/stores/gymshark.com"},"scan_requested":false,"scan_job_id":null},{"input":"notastore.example","match":"no_match","reason":"not_in_corpus","store":null,"scan_requested":false,"scan_job_id":null}],"billed":{"lookup_cached":1,"lookup_live":0}}},"EnrichResult":{"type":"object","properties":{"input":{"type":"string","description":"The input exactly as sent.","example":"https://www.allbirds.com/products/wool-runner"},"match":{"$ref":"#/components/schemas/MatchOutcome"},"reason":{"anyOf":[{"$ref":"#/components/schemas/NoMatchReason"},{"type":"null"}],"description":"Set when `match` is `no_match`; otherwise `null`."},"store":{"anyOf":[{"$ref":"#/components/schemas/Store"},{"type":"null"}],"description":"The store when `match` is `matched` or `stale`; otherwise `null`."},"scan_requested":{"type":"boolean","description":"Whether a scan was queued for this input as a result of `refresh: true`.","example":false},"scan_job_id":{"type":["string","null"],"description":"Job id for the queued scan, or `null`.","example":null}},"required":["input","match","reason","store","scan_requested","scan_job_id"]},"MatchOutcome":{"type":"string","enum":["matched","stale","no_match","error"],"description":"`matched` is a store with a completed observation inside the plan freshness window. `stale` is matched but older than that window; the profile is still returned and billed, and `refresh` may be requested. `no_match` means the domain is not in the corpus; it says nothing about whether the site is a store. `error` means we could not answer for this input; it is not billed."},"NoMatchReason":{"type":"string","enum":["not_in_corpus","invalid_domain","not_ecommerce","blocked"],"description":"`not_in_corpus`: never seen. `invalid_domain`: input did not canonicalize to a public registrable domain. `not_ecommerce`: observed and classified as not a store. `blocked`: the domain is on a policy denylist."},"EnrichRequest":{"type":"object","properties":{"domains":{"type":"array","items":{"type":"string","minLength":3,"maxLength":253},"minItems":1,"maxItems":100,"description":"Up to 100 hostnames or URLs. Duplicates after canonicalization are collapsed and billed once.","example":["gymshark.com","https://www.allbirds.com/products/wool-runner","notastore.example"]},"refresh":{"type":"boolean","default":false,"description":"When `true`, queue a scan for inputs that are `no_match` (reason `not_in_corpus`) or `stale`. Requires the `write:scans` scope and a plan with live refreshes. The response still reflects current data; the scan completes later. Billed as `lookup_live` per queued domain at queue time.","example":false}},"required":["domains"]},"TechnologyPage":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Technology"},"description":"Items on this page."},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page, or `null` on the last page. Pass it back as `cursor`. Cursors stay valid for 24 hours.","example":"eyJhZnRlciI6IjIwMjYtMDktMDhUMDQ6MTI6MzFaIn0"}},"required":["data","next_cursor"]},"Technology":{"type":"object","properties":{"slug":{"type":"string","description":"Canonical identifier, stable across REST, MCP, webhooks, and adapters. Use this as the join key; `name` is display text.","example":"klaviyo"},"name":{"type":"string","description":"Display name.","example":"Klaviyo"},"kind":{"$ref":"#/components/schemas/TechnologyKind"},"category":{"type":"string","description":"Natural-language category slug, one per technology.","example":"email-marketing"},"vendor":{"type":["string","null"],"description":"Vendor or developer name when known.","example":"Klaviyo, Inc."},"website":{"type":["string","null"],"format":"uri","description":"Vendor website.","example":"https://www.klaviyo.com"},"listing_url":{"type":["string","null"],"format":"uri","description":"Public OngoingAI page for this technology.","example":"https://ongoing.ai/apps/klaviyo"}},"required":["slug","name","kind","category","vendor","website","listing_url"],"description":"One entry in the canonical technology vocabulary."},"TechnologyKind":{"type":"string","enum":["platform","app","service","theme"],"description":"`platform` is the commerce platform itself (Shopify, WooCommerce). `app` is a platform marketplace listing. `service` is a vendor detected outside a marketplace (payments, analytics, DNS-verified SaaS). `theme` is a storefront theme."}},"parameters":{}},"paths":{"/v1/health":{"get":{"operationId":"getHealth","tags":["Service"],"summary":"Service health","description":"Liveness and build identity. Unauthenticated and unmetered.","x-scope":"none","x-billing-unit":"free","x-agent-notes":"Call this to confirm connectivity before diagnosing an authentication problem. It never requires a key.","responses":{"200":{"description":"Service is up.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}}}}},"/":{"get":{"operationId":"getIndex","tags":["Service"],"summary":"What this host serves","description":"Discovery document for the host: the REST base url, the GraphQL endpoint, where the OpenAPI document lives, and where to get a key. Unauthenticated, unmetered, and static — it reads nothing and says nothing about system health.","x-scope":"none","x-billing-unit":"free","x-mcp":false,"x-agent-notes":"Start here when you know only the hostname. Follow `rest.openapi_url` for the machine-readable description of every operation rather than guessing paths. A 200 here means the host is reachable, not that any dependency is healthy; use getHealth for that.","responses":{"200":{"description":"The service index.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiIndex"}}}}}}},"/v1":{"get":{"operationId":"getVersionIndex","tags":["Service"],"summary":"Operations served at v1","description":"The operations this build serves, as operation id to URL. Unauthenticated and unmetered. An operation defined in the contract but not yet implemented is omitted here.","x-scope":"none","x-billing-unit":"free","x-mcp":false,"x-agent-notes":"Use this to check what a deployment actually serves before calling it: the contract describes the whole surface, this lists what is live. Resolve `{}` placeholders yourself; they are path parameters.","responses":{"200":{"description":"The version index.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VersionIndex"}}}}}}},"/v1/account":{"get":{"operationId":"getAccount","tags":["Account"],"summary":"Validate the key and discover capabilities","description":"Returns the workspace, the key used for this request, the plan limits in force, and the current billing period. Make this the first call of any integration: it tells you which scopes you hold and how much allowance remains before you spend any of it.","security":[{"ApiKey":[]}],"x-scope":"any","x-billing-unit":"free","x-mcp":false,"x-agent-notes":"Free and safe to call repeatedly. Use `plan.limits.rpm` and `concurrency` to pace requests and `period.used` versus `period.included` to decide whether a bulk run fits the remaining allowance. A 401 here means the key is wrong or revoked, not that the service is down.","responses":{"200":{"description":"The key is valid.","content":{"application/json":{"example":{"workspace":{"id":"ws_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","name":"Acme Agency"},"key":{"id":"key_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","label":"Clay production","prefix":"oai_live_a1b2","environment":"live","scopes":["read:stores","read:signals"],"expires_at":null},"plan":{"slug":"growth","limits":{"rpm":300,"concurrency":10,"enrich_batch_max":100,"freshness_days":30,"history_days":365,"live_refreshes_per_period":500}},"period":{"starts_at":"2026-09-01T00:00:00Z","ends_at":"2026-10-01T00:00:00Z","included":{"lookup_cached":10000,"lookup_live":500,"history_query":10000,"refresh_requested":0},"used":{"lookup_cached":1234,"lookup_live":7,"history_query":88,"refresh_requested":0}}},"schema":{"$ref":"#/components/schemas/Account"}}}},"401":{"description":"Missing, malformed, revoked, or expired key.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Missing or invalid API key.","request_id":"req_01J9X4K6ZP3M8Q2R5T7V9W1Y3A"}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/usage":{"get":{"operationId":"getUsage","tags":["Account"],"summary":"Usage this period","description":"Consumption by billing unit for the current period, in total and per key. Updated within five minutes of each request.","security":[{"ApiKey":[]}],"x-scope":"any","x-billing-unit":"free","x-mcp":false,"x-agent-notes":"Free. Read `period.included` minus `period.used` per unit to size a batch. Per-key rows include revoked keys that spent units this period so the totals reconcile.","responses":{"200":{"description":"Usage for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"}}}},"401":{"description":"Missing or invalid key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/stores/{domain}":{"get":{"operationId":"getStore","tags":["Stores"],"summary":"Store profile by domain","description":"The current profile of one store from completed observations: platform, technologies with install state and dates, geography, industry, catalog aggregates, lifecycle status, and the last five confirmed signals. Cacheable; identical inputs return identical bodies until the next completed observation.","security":[{"ApiKey":[]}],"x-scope":"read:stores","x-billing-unit":"lookup_cached","x-mcp":true,"x-agent-notes":"One lookup_cached unit on 200; nothing on 404. A 404 with code not_found means the domain is not in the corpus, which is not evidence that the site is not a store; use POST /v1/stores/enrich with refresh: true (if the key has write:scans) to request an observation. Before concluding a technology is absent, check observation.scope: only a `full` scope supports that reading. Never infer an uninstall from a missing entry when last_completed_scan_at is old; use /history for confirmed removals.","parameters":[{"schema":{"type":"string","minLength":3,"maxLength":253,"description":"Hostname of the store, for example `gymshark.com`. A full URL also works but must be percent-encoded, because this is a single path segment. Either way the value is canonicalized server-side to the registrable domain; the response carries the canonical `domain` and, when different, the `storefront_host` that actually serves the shop.","example":"gymshark.com"},"required":true,"description":"Hostname of the store, for example `gymshark.com`. A full URL also works but must be percent-encoded, because this is a single path segment. Either way the value is canonicalized server-side to the registrable domain; the response carries the canonical `domain` and, when different, the `storefront_host` that actually serves the shop.","name":"domain","in":"path"},{"schema":{"type":"string","description":"Optional caller-supplied request id (8 to 64 characters, `A-Z a-z 0-9 _ -`). Echoed back on the response; otherwise the API generates one.","example":"clay-row-48213"},"required":false,"description":"Optional caller-supplied request id (8 to 64 characters, `A-Z a-z 0-9 _ -`). Echoed back on the response; otherwise the API generates one.","in":"header","name":"x-request-id"}],"responses":{"200":{"description":"The store.","content":{"application/json":{"example":{"match":"matched","store":{"domain":"gymshark.com","storefront_host":"www.gymshark.com","storefront_id":"sf_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","brand_group_id":"bg_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","name":"Gymshark","platform":{"slug":"shopify","name":"Shopify","confidence":"high","first_observed_at":"2025-11-02T09:41:00Z","last_confirmed_at":"2026-09-08T04:12:31Z"},"status":{"state":"active_storefront","as_of":"2026-09-08T04:12:31Z"},"technologies":[{"slug":"klaviyo","name":"Klaviyo","category":"email-marketing","install_state":"active","confidence":"high","first_observed_at":"2026-02-14T11:05:12Z","last_confirmed_at":"2026-09-08T04:12:31Z"},{"slug":"gorgias","name":"Gorgias","category":"customer-support","install_state":"active","confidence":"high","first_observed_at":"2026-08-30T03:58:10Z","last_confirmed_at":"2026-09-08T04:12:31Z"},{"slug":"yotpo","name":"Yotpo","category":"reviews","install_state":"configured","confidence":"medium","first_observed_at":"2026-01-20T08:00:00Z","last_confirmed_at":"2026-09-08T04:12:31Z"}],"geography":{"country":"GB","basis":"observed"},"industry":{"slug":"apparel","basis":"classified"},"catalog":{"product_count":1284,"available_count":null,"currency":"GBP","price_range":{"p25":28,"median":34,"p75":98},"as_of":"2026-09-09T02:20:00Z","coverage":"first_page"},"observation":{"last_completed_scan_at":"2026-09-08T04:12:31Z","scope":"full","coverage_note":null},"recent_signals":[{"id":"evt_7Q2M4K9ZP3R5T7V9W1Y3A6B8C","type":"technology_added","technology":"gorgias","from":null,"to":null,"effective_at":"2026-08-30T03:58:10Z","confirmed_at":"2026-09-01T04:02:44Z","confidence":"high"}],"profile_url":"https://ongoing.ai/stores/gymshark.com"}},"schema":{"$ref":"#/components/schemas/StoreResponse"}}}},"401":{"description":"Missing or invalid key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Key lacks `read:stores`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Domain is not in the corpus or did not canonicalize. Not evidence that the site is not a store.","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Domain is not in the corpus. Request an observation with refresh: true.","request_id":"req_01J9X4K6ZP3M8Q2R5T7V9W1Y3A"}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limit exceeded; honor `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/stores/enrich":{"post":{"operationId":"enrichStores","tags":["Stores"],"summary":"Enrich up to 100 domains","description":"Batch form of the store profile. Each input is canonicalized and answered independently; the response preserves input order. Matched and stale inputs return the full store object. No-match inputs return a reason and are not billed. With `refresh: true` and the `write:scans` scope, unknown or stale domains are queued for observation and the result is marked `scan_requested`.","security":[{"ApiKey":[]}],"x-scope":"read:stores","x-billing-unit":"lookup_cached","x-mcp":true,"x-agent-notes":"Bills one lookup_cached per matched or stale result and one lookup_live per queued scan; no_match and error results are free. Send an Idempotency-Key on every retry so a timeout cannot double-bill. Keep batches at or under plan.limits.enrich_batch_max. Results with match: no_match and reason: not_in_corpus are unknown to us, not confirmed non-stores. A scan_requested result completes later; poll GET /v1/stores/{domain} after a few minutes or subscribe to events.","parameters":[{"schema":{"type":"string","description":"Optional caller-supplied request id (8 to 64 characters, `A-Z a-z 0-9 _ -`). Echoed back on the response; otherwise the API generates one.","example":"clay-row-48213"},"required":false,"description":"Optional caller-supplied request id (8 to 64 characters, `A-Z a-z 0-9 _ -`). Echoed back on the response; otherwise the API generates one.","in":"header","name":"x-request-id"},{"schema":{"type":"string","minLength":8,"maxLength":128,"description":"Optional. Replaying the same key with the same body within 24 hours returns the original response with `Idempotent-Replayed: true` and bills nothing. Same key with a different body returns `409 conflict`.","example":"clay-run-2026-09-10-batch-12"},"required":false,"description":"Optional. Replaying the same key with the same body within 24 hours returns the original response with `Idempotent-Replayed: true` and bills nothing. Same key with a different body returns `409 conflict`.","in":"header","name":"idempotency-key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichRequest"}}}},"responses":{"200":{"description":"One result per input.","content":{"application/json":{"example":{"request_id":"req_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","results":[{"input":"gymshark.com","match":"matched","reason":null,"store":{"domain":"gymshark.com","storefront_host":"www.gymshark.com","storefront_id":"sf_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","brand_group_id":"bg_01J9X4K6ZP3M8Q2R5T7V9W1Y3A","name":"Gymshark","platform":{"slug":"shopify","name":"Shopify","confidence":"high","first_observed_at":"2025-11-02T09:41:00Z","last_confirmed_at":"2026-09-08T04:12:31Z"},"status":{"state":"active_storefront","as_of":"2026-09-08T04:12:31Z"},"technologies":[{"slug":"klaviyo","name":"Klaviyo","category":"email-marketing","install_state":"active","confidence":"high","first_observed_at":"2026-02-14T11:05:12Z","last_confirmed_at":"2026-09-08T04:12:31Z"},{"slug":"gorgias","name":"Gorgias","category":"customer-support","install_state":"active","confidence":"high","first_observed_at":"2026-08-30T03:58:10Z","last_confirmed_at":"2026-09-08T04:12:31Z"},{"slug":"yotpo","name":"Yotpo","category":"reviews","install_state":"configured","confidence":"medium","first_observed_at":"2026-01-20T08:00:00Z","last_confirmed_at":"2026-09-08T04:12:31Z"}],"geography":{"country":"GB","basis":"observed"},"industry":{"slug":"apparel","basis":"classified"},"catalog":{"product_count":1284,"available_count":null,"currency":"GBP","price_range":{"p25":28,"median":34,"p75":98},"as_of":"2026-09-09T02:20:00Z","coverage":"first_page"},"observation":{"last_completed_scan_at":"2026-09-08T04:12:31Z","scope":"full","coverage_note":null},"recent_signals":[{"id":"evt_7Q2M4K9ZP3R5T7V9W1Y3A6B8C","type":"technology_added","technology":"gorgias","from":null,"to":null,"effective_at":"2026-08-30T03:58:10Z","confirmed_at":"2026-09-01T04:02:44Z","confidence":"high"}],"profile_url":"https://ongoing.ai/stores/gymshark.com"},"scan_requested":false,"scan_job_id":null},{"input":"notastore.example","match":"no_match","reason":"not_in_corpus","store":null,"scan_requested":false,"scan_job_id":null}],"billed":{"lookup_cached":1,"lookup_live":0}},"schema":{"$ref":"#/components/schemas/EnrichResponse"}}}},"400":{"description":"Malformed body or more than the batch maximum.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing or invalid key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Key lacks `read:stores`, or `refresh` without `write:scans`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Idempotency key reused with a different body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limit exceeded; honor `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/technologies":{"get":{"operationId":"listTechnologies","tags":["Technologies"],"summary":"Technology vocabulary","description":"The canonical list of platforms, apps, services, and themes the API can report, with categories. Slugs here are the same slugs used in store profiles, signals, webhooks, and MCP tools.","security":[{"ApiKey":[]}],"x-scope":"read:stores","x-billing-unit":"free","x-mcp":true,"x-agent-notes":"Free. Resolve a user-supplied name to a slug here before filtering signals or comparing stores; never guess a slug. The list is paginated; follow next_cursor until null for a complete vocabulary, or use q for a prefix search.","parameters":[{"schema":{"allOf":[{"$ref":"#/components/schemas/TechnologyKind"},{"description":"Filter to one kind."}]},"required":false,"description":"Filter to one kind.","name":"kind","in":"query"},{"schema":{"type":"string","description":"Filter to one category slug.","example":"email-marketing"},"required":false,"description":"Filter to one category slug.","name":"category","in":"query"},{"schema":{"type":"string","minLength":2,"maxLength":64,"description":"Case-insensitive prefix match on `name` or `slug`.","example":"klav"},"required":false,"description":"Case-insensitive prefix match on `name` or `slug`.","name":"q","in":"query"},{"schema":{"type":"string","description":"Cursor from a previous page."},"required":false,"description":"Cursor from a previous page.","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"Page size, 1 to 200.","example":50},"required":false,"description":"Page size, 1 to 200.","name":"limit","in":"query"}],"responses":{"200":{"description":"A page of technologies.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TechnologyPage"}}}},"401":{"description":"Missing or invalid key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/technologies/{slug}":{"get":{"operationId":"getTechnology","tags":["Technologies"],"summary":"One technology","description":"Metadata for one slug.","security":[{"ApiKey":[]}],"x-scope":"read:stores","x-billing-unit":"free","x-mcp":false,"x-agent-notes":"Free. A 404 means the slug is not in the vocabulary; check spelling with listTechnologies and q.","parameters":[{"schema":{"type":"string","description":"Technology slug from the vocabulary.","example":"klaviyo"},"required":true,"description":"Technology slug from the vocabulary.","name":"slug","in":"path"}],"responses":{"200":{"description":"The technology.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Technology"}}}},"401":{"description":"Missing or invalid key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Unknown slug.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}}},"webhooks":{}}