{"openapi":"3.1.0","info":{"title":"AutoSugges runtime API","version":"v1","description":"Edge autocomplete for lists of values. The publishable key is public; origin controls and rate limits are enforced at the edge."},"servers":[{"url":"https://runtime.autosugges.com"}],"paths":{"/health":{"get":{"operationId":"getHealth","summary":"Liveness probe.","responses":{"200":{"description":"The runtime is serving.","content":{"application/json":{"schema":{"type":"object","required":["status","service"],"properties":{"status":{"type":"string","const":"ok"},"service":{"type":"string"},"env":{"type":"string"},"build":{"type":"string"}}}}}}}}},"/v1/bootstrap":{"get":{"operationId":"getBootstrap","summary":"Resolves the list identity, the active version hash and the effective query policy for this key. Call once per session before querying.","security":[{"bearerAuth":[]},{}],"parameters":[{"name":"key","in":"query","required":true,"description":"The publishable key. It is public by design and travels as a query parameter, never an Authorization header.","schema":{"type":"string"}},{"name":"locale","in":"query","required":false,"description":"Optional BCP-47 tag; falls back to the list default.","schema":{"type":"string"}}],"responses":{"200":{"description":"Resolved list and effective policy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BootstrapResult"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/v1/query":{"get":{"operationId":"query","summary":"Returns the pre-ranked suggestions for one query.","description":"Counted against your plan. A query shorter than the list minimum is rejected and not billed. When the allowance is spent the response is a 200 carrying `code: quota_exceeded` and no `items` field.","security":[{"bearerAuth":[]},{}],"parameters":[{"name":"key","in":"query","required":true,"description":"The publishable key. It is public by design and travels as a query parameter, never an Authorization header.","schema":{"type":"string"}},{"name":"q","in":"query","required":true,"description":"The text typed so far.","schema":{"type":"string"}},{"name":"locale","in":"query","required":false,"description":"Optional BCP-47 tag; falls back to the list default.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Maximum suggestions to return.","schema":{"type":"integer","minimum":1}},{"name":"parent","in":"query","required":false,"description":"Hierarchical lists only: narrow to the children of this item id or value.","schema":{"type":"string"}},{"name":"fields","in":"query","required":false,"description":"Comma-separated optional suggestion fields to return.","schema":{"type":"string"}}],"responses":{"200":{"description":"Pre-ranked suggestions, or the quota_exceeded state.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/QueryResult"},{"$ref":"#/components/schemas/ErrorBody"}]}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/v1/selection":{"post":{"operationId":"reportSelection","summary":"Reports which suggestion the user chose, so ranking can improve. Optional: skipping it degrades ranking quality and nothing else.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelectionRequest"}}}},"responses":{"200":{"description":"Selection recorded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelectionResult"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/v1/items":{"post":{"operationId":"createItem","summary":"Creates a list item at runtime.","description":"Off unless the list enables creation. Tenant and user scope need an access token carrying `list:<id>:create`. Not billed. A duplicate returns the existing item with `created: false`.","security":[{"bearerAuth":[]}],"parameters":[{"name":"key","in":"query","required":true,"description":"The publishable key. It is public by design and travels as a query parameter, never an Authorization header.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateItemRequest"}}}},"responses":{"200":{"description":"The created or existing item.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateItemResult"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/api/v1/token":{"servers":[{"url":"https://app.autosugges.com"}],"post":{"operationId":"mintAccessToken","summary":"Exchanges a secret key for a one-hour access token. Server to server only.","description":"Never call from a browser or mobile bundle; the secret key belongs on your server.","security":[{"secretKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintTokenRequest"}}}},"responses":{"200":{"description":"A short-lived access token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintTokenResult"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Access token minted by your server. Only for lists whose policy requires one."},"secretKey":{"type":"http","scheme":"bearer","description":"Your secret key. Server-side only."}},"responses":{"Error401":{"description":"Typed error. `code` is one of: invalid_key, token_expired, invalid_token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"Error403":{"description":"Typed error. `code` is one of: origin_not_allowed, subscription_required, challenge_failed, forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"Error404":{"description":"Typed error. `code` is one of: invalid_list, resource_removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"Error409":{"description":"Typed error. `code` is one of: list_not_published, domain_validation_failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"Error400":{"description":"Typed error. `code` is one of: query_too_long, invalid_request, invalid_domain.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"Error429":{"description":"Typed error. `code` is one of: rate_limited.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"Error422":{"description":"Typed error. `code` is one of: publish_validation_failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"Error500":{"description":"Typed error. `code` is one of: compile_failed, internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"Error503":{"description":"Typed error. `code` is one of: artifact_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}}},"schemas":{"ErrorBody":{"type":"object","required":["code","message","requestId"],"properties":{"code":{"type":"string","enum":["invalid_key","origin_not_allowed","invalid_list","subscription_required","list_not_published","token_expired","invalid_token","quota_exceeded","query_too_short","query_too_long","invalid_request","rate_limited","challenge_failed","publish_validation_failed","compile_failed","artifact_unavailable","resource_removed","invalid_domain","domain_validation_failed","forbidden","internal_error"]},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"object","additionalProperties":true},"docsUrl":{"type":"string"},"remediation":{"type":"string"},"retryAfter":{"type":"number","description":"Seconds. Present only where a retry is safe."}},"x-error-codes":{"invalid_key":{"status":401,"retryable":false,"remediation":"The publishable key is wrong, revoked or rotated. Check the key in the AutoSugges dashboard. Do not retry with the same key."},"origin_not_allowed":{"status":403,"retryable":false,"remediation":"The requesting origin is not on this key's allow-list. Add the origin in the dashboard. Not billed."},"invalid_list":{"status":404,"retryable":false,"remediation":"The key resolves to no list, or the list was deleted. Nothing to retry."},"subscription_required":{"status":403,"retryable":false,"remediation":"The list is shared and this consumer has no active subscription to it. Subscribe, or use a list you own."},"list_not_published":{"status":409,"retryable":false,"remediation":"The list exists but has never been published, so there is no artifact to serve. Publish it once from the dashboard."},"token_expired":{"status":401,"retryable":false,"remediation":"The access token is past its expiry. Mint a fresh one on your server and retry once. Never extend expiry on the client."},"invalid_token":{"status":401,"retryable":false,"remediation":"The access token failed signature or scope verification. Mint a new one; do not retry the same token."},"quota_exceeded":{"status":200,"retryable":false,"remediation":"The allowance for this billing scope is spent. `details.scope` says which allowance — `subscription` or `key`. The response carries no items at all, real or synthetic: render an upgrade path, and do not feed it into selection analytics. It clears at the next billing period."},"query_too_short":{"status":200,"retryable":false,"remediation":"The query is below the list's `minQueryChars` (`details.minQueryChars`). Do not issue the request at all until the input reaches it. Not billed."},"query_too_long":{"status":400,"retryable":false,"remediation":"The query exceeds the server maximum (`details.maxQueryChars`). Trim the input before sending; this is a malformed request, not something a user types."},"invalid_request":{"status":400,"retryable":false,"remediation":"The request is malformed — a missing parameter or an unusable value. `details` names what. Fix the call; retrying unchanged cannot help."},"rate_limited":{"status":429,"retryable":true,"remediation":"Too many requests for this key, subscription or IP. Honour the `retryAfter` seconds in the body before retrying, and check that the input is actually debounced."},"challenge_failed":{"status":403,"retryable":false,"remediation":"A bot challenge was not satisfied on a session-establishing surface. Re-present the challenge. Not billed."},"publish_validation_failed":{"status":422,"retryable":false,"remediation":"A publish was rejected by validation (duplicates, an unresolved parent, a hierarchy cycle). The previously active version keeps serving. Fix the data and publish again."},"compile_failed":{"status":500,"retryable":true,"remediation":"Compilation of a new version failed. The previously active version keeps serving; nothing at runtime changed. Retry the publish after fixing the reported cause."},"artifact_unavailable":{"status":503,"retryable":true,"remediation":"A published artifact could not be read at this edge, usually mid-propagation. Retryable: wait the `retryAfter` seconds and retry once. Do not render a partial or stale result set alongside a fresh one."},"resource_removed":{"status":404,"retryable":false,"remediation":"The resource was deleted. Stop requesting it; there is nothing to retry."},"invalid_domain":{"status":400,"retryable":false,"remediation":"The submitted domain or slug is not valid or is reserved. Choose another."},"domain_validation_failed":{"status":409,"retryable":false,"remediation":"A custom-domain DNS or TLS validation did not complete. Re-check the DNS records shown in the dashboard, then revalidate."},"forbidden":{"status":403,"retryable":false,"remediation":"Your account is signed in but your workspace role does not permit this action. Ask an owner or admin to change your role, or use an account that has it."},"internal_error":{"status":500,"retryable":true,"remediation":"An unexpected server-side failure. Report the `requestId` from the response. Retry at most once, with backoff."}}},"Suggestion":{"type":"object","required":["itemId","value","displayValue","displayOrder","position"],"properties":{"itemId":{"type":"string","description":"Stable identifier. Use it as the React/list key."},"value":{"type":"string","description":"The canonical value — what you store."},"displayValue":{"type":"string","description":"The locale-resolved label — what you render. Not the same field as `value`."},"displayOrder":{"type":"number","description":"The owner's configured display order."},"position":{"type":"number","description":"1-based position in the returned ranking."},"ancestors":{"type":"array","description":"The precomputed hierarchy chain, root first, excluding the item itself — `{ itemId, value, displayValue, hierarchyLevel? }`. Use it to auto-fill parent form fields. Absent when the item has no ancestors; never an empty array.","items":{"type":"object","required":["itemId","value","displayValue"],"properties":{"itemId":{"type":"string"},"value":{"type":"string"},"displayValue":{"type":"string"},"hierarchyLevel":{"type":"string"}}}},"flag":{"type":"string"},"emoji":{"type":"string"},"icon":{"type":"string"},"meta":{"type":"object","additionalProperties":{"type":"string"}}}},"QueryResult":{"type":"object","required":["requestId","list","locale","source","prefix","filtered","totalEligible","items"],"properties":{"requestId":{"type":"string"},"list":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid"}}},"locale":{"type":"string"},"filtered":{"type":"boolean"},"totalEligible":{"type":"number"},"items":{"type":"array","items":{"$ref":"#/components/schemas/Suggestion"}}}},"BootstrapResult":{"type":"object","required":["requestId","list","activeVersionHash","queryPolicy"],"properties":{"requestId":{"type":"string","description":"Correlation id for this bootstrap call."},"list":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid","description":"The canonical list this key resolves to. Never supplied by the client."}}},"activeVersionHash":{"type":"string","description":"The published version currently serving. Compare it to a stored hash to decide whether a cached local copy is stale."},"queryPolicy":{"type":"object","required":["minQueryChars","debounceMs"],"properties":{"minQueryChars":{"type":"number","description":"Minimum characters before a query is legal. Never below 2, and never hardcoded — a shorter query is rejected and not billed."},"debounceMs":{"type":"number","description":"How long to wait after the last keystroke before issuing a query."},"defaultResultLimit":{"type":"number","description":"How many suggestions a list returns by default. Informational: the server already returns its ranked set, so the client does not send this back."},"rememberLastSelection":{"type":"boolean","description":"Tenant policy for prefilling a previously chosen item. Treat anything other than literal `true` as off."}}},"ownerTenantId":{"type":"string"},"hierarchical":{"type":"boolean"},"localePolicy":{"type":"object","properties":{"defaultLocale":{"type":"string"},"supportedLocales":{"type":"array","items":{"type":"string"}}}},"componentPolicy":{"type":"object","additionalProperties":true}}},"SelectionRequest":{"type":"object","required":["key","selectionId","queryRequestId","listId","itemId","query","position"],"description":"`key` field of the JSON body, alongside `selectionId`, `queryRequestId`, `listId`, `itemId`, `query` and `position`","properties":{"key":{"type":"string","description":"The publishable key."},"selectionId":{"type":"string","description":"Idempotency key; duplicates are ignored."},"queryRequestId":{"type":"string","description":"The requestId of the query that surfaced the item."},"listId":{"type":"string"},"itemId":{"type":"string"},"query":{"type":"string","maxLength":512},"position":{"type":"integer","minimum":1,"description":"1-based position in the result set."}}},"SelectionResult":{"type":"object","required":["selectionId"],"properties":{"selectionId":{"type":"string"}}},"CreateItemRequest":{"type":"object","required":["value"],"properties":{"value":{"type":"string"},"displayValue":{"type":"string"},"parentItemId":{"type":"string"},"locale":{"type":"string"}}},"CreateItemResult":{"type":"object","required":["requestId","created","scope","item"],"properties":{"requestId":{"type":"string"},"created":{"type":"boolean"},"scope":{"type":"string","enum":["tenant","user"]},"item":{"$ref":"#/components/schemas/Suggestion"}}},"MintTokenRequest":{"type":"object","properties":{"listIds":{"type":"array","items":{"type":"string"}},"listId":{"type":"string"},"create":{"type":"object","required":["listId"],"properties":{"listId":{"type":"string"},"actorId":{"type":"string"}}}}},"MintTokenResult":{"type":"object","required":["accessToken","tokenType","expiresIn","expiresAt","applicationId","listIds","scope","requestId"],"properties":{"accessToken":{"type":"string"},"tokenType":{"type":"string","const":"Bearer"},"expiresIn":{"type":"integer","description":"Seconds; one hour."},"expiresAt":{"type":"integer","description":"Unix seconds."},"applicationId":{"type":"string"},"listIds":{"type":"array","items":{"type":"string"}},"scope":{"type":"array","items":{"type":"string"}},"actorId":{"type":"string"},"requestId":{"type":"string"}}}}}}