# Integration contract & APIs

> The documented integration surfaces for engineering teams — placement anchor, wire contract, and failure modes.

The kit band ships inside the same Poneva runtime the embed script loads; Poneva enables
and wires it for your store as part of Agentic Kits onboarding, so most teams never touch
this page. For teams that want precise control, the documented surfaces are below. This
page is also where future raw-API exposure for power users will land — see the
[roadmap](./roadmap.md).

## Placement

The band fires on one of two triggers. On a **search page** it reads the shopper's search
term structurally from the page URL (common query parameters such as `q`, `query`,
`search`, or a configured one). On a **category page** — where there is no search term — it
matches the current page URL against the glob-lite patterns you configured (for example
`https://www.apotea.se/halsont*`, where `*` matches anything after the prefix); a typed
search term always takes precedence over a category match. Either way it mounts into your
results container, after a configurable number of product cards — the "show the kit after
this many products" setting (default 4). It resolves its anchor in this order: your
configured selectors, then an element carrying the `data-skaii-agentic-anchor` attribute,
then conservative structural fallbacks; when it can't count product cards there (an empty
container, or a bare anchor element) it falls back to mounting above the container. Adding
`data-skaii-agentic-anchor` to your results container is the simplest way to pin
exact placement.

## The wire contract

The band calls one public, rate-limited endpoint:

```
POST https://poneva.com/storefront/search
{ "demo_id": "<your store id>", "query": "<search term>", "page_url": "<optional current page URL>", "session_id": "<optional>" }
```

On a search page the band sends `query`; on a category page it sends `page_url` (its
current location) and an empty `query`, and the server matches that URL to a configured
category trigger. A request carries a `query` or a `page_url` (or both — `query` wins).

The response is `{ base, plan, rendering }`. When nothing should render (surface not
published, term/category not live, no servable kits, or the page matches no trigger),
`base` is `null` and the page stays native. Otherwise `rendering` carries the kits to display, plus optional
quick-filter chips. A chip click re-queries the same session via
`POST /storefront/search/filter` with `{ "session_id": ..., "filter_id": ... }` — a
constrained re-run within the current term, never a new search.

## Failure modes

Every failure mode — network error, missing anchor, unpublished surface, empty term —
fails closed to your native experience.
