# AI tasks, models, pricing, and results

## Discover capabilities

Load models from `GET https://task.starhk.uk/v1/models?site_id=<SITE_ID>` and effective pricing from `GET /v1/pricing/rules?site_id=<SITE_ID>`, using the user's bearer token where required. Use returned aliases in the `model` field. Do not show a provider selector.

## Create and poll

```js
const idempotencyKey = crypto.randomUUID();
const created = await fetch('https://task.starhk.uk/v1/tasks', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${accessToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    site_id: SITE_ID,
    model: 'nano-banana-2',
    task_type: 'text-to-image',
    input: { prompt: 'A calm Hong Kong harbour at dawn', quality: '1K' },
    idempotency_key: idempotencyKey,
  }),
}).then(r => r.json());

const taskId = created.data.task_id;
```

Poll `created.data.poll_url` (or `GET /v1/tasks/:id?site_id=...`) about every 3–5 seconds. Stop at `succeeded`, `failed`, or `cancelled`; use a 15–20 minute UI timeout for long video/audio jobs without cancelling the server task automatically.

## Charging guarantees

- Star Task resolves the site's effective price and coordinates point consumption/refund.
- The create response contains authoritative `cost_points`.
- Reusing the same idempotency key for the same user action avoids duplicate tasks and duplicate charging.
- A failed task follows Star Task's refund policy. Frontends must not call a point-consume endpoint themselves.

## Result handling

Render only Star Task output URLs. Image, video, and audio outputs from RokoAPI are copied to Star Task R2 storage before success is exposed. If persistence fails, the Roko task is failed/retried rather than reporting a temporary upstream link as durable.

Provider routing is internal. A RokoAPI-selected task never falls back to Evolink or GRSAI; RokoAPI performs its own channel routing.
