# Warm-up: Mosaic API reference

> Warm-up in Mosaic’s local REST API: 12 routes, each with its method, path, fields, what it returns and the errors it names.

Source: https://mosaicbrowser.com/docs/api/warmup

**Preparing and testing** REST API

## Warm-up

The cookie robot: browse the web as a profile so it stops looking brand new. An empty cookie jar and no history is scored as risk on its own, however good the fingerprint is.

- [GETList warm-up presets](#warmup-presets)
- [POSTPreview the site list](#warmup-plan)
- [POSTWarm a profile up](#warmup-run)
- [POSTStop a warm-up](#warmup-cancel)
- [GETList warm-ups in progress](#warmup-running)
- [GETList saved plans](#list-warmup-plans)
- [GETRead one plan](#get-warmup-plan)
- [POSTCreate a plan](#create-warmup-plan)
- [PATCHChange a plan](#update-warmup-plan)
- [DELETEDelete a plan](#delete-warmup-plan)
- [POSTWarm many profiles with one plan](#warmup-run-many)
- [POSTStop a batch](#warmup-cancel-all)

## [List warm-up presets](#warmup-presets)

GET`/api/v1/warmup/presets`

The built-in site lists — general browsing, social, shopping, technology — with the sites each contains, plus the default options a run uses when you pass none.

#### Returns

`{ total, presets: Array<{ id, label, description, siteCount, sites }>, defaults: WarmupOptions }`

## [Preview the site list](#warmup-plan)

POST`/api/v1/profiles/:id/warmup/plan`

Returns the sites a run with these options would visit, in order, without visiting anything. The sample is random, so calling it twice gives two different plans.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id`required | `string` | The record’s id. |

#### Body

`Partial<WarmupOptions>`. Same options as a run.

#### Returns

`{ sites: string[] }`

## [Warm a profile up](#warmup-run)

POST`/api/v1/profiles/:id/warmup`

Opens the profile’s own browser — its fingerprint, its proxy — visits the planned sites, dwells for a sampled time on each, scrolls the way a wheel does, optionally dismisses consent banners and follows same-origin links, then closes the browser cleanly so everything collected is flushed to disk. Long-running by design: a default run takes minutes. The profile must not already be running, because the robot needs its own session. A site that fails to load is recorded and skipped rather than ending the run.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id`required | `string` | The record’s id. |

#### Body

| Field | Type | What it is |
| --- | --- | --- |
| `preset` | `"general" \| "social" \| "shopping" \| "tech"` | Which built-in list to sample from. |
| `sites` | `string[]` | Your own sites. Anything here replaces the preset entirely. |
| `siteCount` | `number` | How many sites to visit from the pool. Default 8. |
| `minSecondsPerSite` | `number` | Lower bound of the dwell time. Default 12. |
| `maxSecondsPerSite` | `number` | Upper bound. Sampled per page, because a constant dwell is itself a pattern. Default 35. |
| `scroll` | `boolean` | Stepped, eased scrolling with occasional corrections. Default true. |
| `followLinks` | `boolean` | Follow same-origin links so the history has depth. Default true. |
| `maxLinksPerSite` | `number` | How many, per site. Default 2. |
| `acceptCookieBanners` | `boolean` | Click through consent dialogs, which gate most of the cookies worth having. Default true. |
| `headless` | `boolean` | Default **false**, and best left that way. `--headless=new` renames the product token to `HeadlessChrome` and drops the real GPU, so every site whose cookies you are collecting is told it is talking to an automated browser with a different fingerprint from the one that will later use them. Set only if you have a reason; the launcher forces a `--user-agent` override when it is on so the token does not leak. |
| `watch` | `boolean` | Default false. Off runs the real, headed browser parked off-screen — invisible, but with the profile’s own renderer. On shows the window so you can watch the run. |

#### Returns

A `WarmupReport` — `{ visited, cookies, seconds, cancelled, sites: WarmupSiteResult[] }`.

#### Errors

- 400 — the profile is already running, or already warming up.

```
curl -X POST -H "Authorization: Bearer $KEY" -H 'content-type: application/json' \
  -d '{"preset":"shopping","siteCount":12}' \
  "$BASE/profiles/$ID/warmup"
```

## [Stop a warm-up](#warmup-cancel)

POST`/api/v1/profiles/:id/warmup/cancel`

Asks the run to stop. It finishes the page it is on and closes the browser cleanly, so the cookies collected so far are kept rather than thrown away.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id`required | `string` | The record’s id. |

#### Returns

`{ cancelled: true }`

## [List warm-ups in progress](#warmup-running)

GET`/api/v1/warmup/running`

Profile ids currently being warmed up.

#### Returns

`{ profileIds: string[] }`

## [List saved plans](#list-warmup-plans)

GET`/api/v1/warmup/plans`

A plan is a named, reusable warm-up: a list of sites plus how to behave on them. It exists because the four built-in presets are a list somebody else wrote, and the sites that matter to an operator are the ones their accounts live on. Every plan carries a whole `WarmupOptions` rather than a subset, so a plan **is** the body `POST /profiles/:id/warmup` would be sent — a saved copy and a run cannot describe two different things.

#### Query parameters

| Field | Type | What it is |
| --- | --- | --- |
| `deleted` | `boolean` | `true` lists the plan trash instead: the same rows, in the same shape, with `deletedAt` set. The trash is a filter over one collection, not a second collection. |

#### Returns

`{ total, plans: WarmupPlan[] }`

## [Read one plan](#get-warmup-plan)

GET`/api/v1/warmup/plans/:id`

The whole plan, including every run option.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id` | `string` | Plan id. |

#### Returns

A `WarmupPlan`.

#### Errors

- 404 — no plan with that id.

## [Create a plan](#create-warmup-plan)

POST`/api/v1/warmup/plans`

The options are checked now rather than at run time. A dwell range the wrong way round, a `siteCount` of zero or a `sites` entry that is not a place a browser can go is refused here — the alternative is discovering it forty profiles into a batch nobody is watching. Nothing is silently repaired: clamping a reversed range would leave the author believing something untrue about a plan that will be used on hundreds of profiles.

#### Body

| Field | Type | What it is |
| --- | --- | --- |
| `name`required | `string` | What the plan is called. |
| `description` | `string` | What it is for. |
| `options` | `Partial<WarmupOptions>` | Anything omitted takes the default. `sites` replaces the preset entirely. |

#### Returns

The created `WarmupPlan`.

#### Errors

- 400 — an unknown field. The run settings go inside `options`.
- 400 — an option is present and wrong; the message names it.

## [Change a plan](#update-warmup-plan)

PATCH`/api/v1/warmup/plans/:id`

Only what you pass changes, including inside `options` — so one field can be sent without restating the rest.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id` | `string` | Plan id. |

#### Body

`Partial<WarmupPlan>`. name, description, options.

#### Returns

The updated `WarmupPlan`.

#### Errors

- 404 — no plan with that id.

## [Delete a plan](#delete-warmup-plan)

DELETE`/api/v1/warmup/plans/:id`

The plan goes and no profile is touched — a plan is a list of places, not a record of anything.

#### Path parameters

| Field | Type | What it is |
| --- | --- | --- |
| `id` | `string` | Plan id. |

#### Returns

`{ deleted: true }`

#### Errors

- 404 — no plan with that id.

## [Warm many profiles with one plan](#warmup-run-many)

POST`/api/v1/warmup/run`

Runs the profiles **one after another**, and that is a correctness point rather than politeness: each run launches that profile’s own browser, so a parallel fan-out is a check-then-act race against `maxConcurrentProfiles` — every call reads the count before any of them registers, all of them pass, and the cap is silently exceeded. Blocks for the whole batch, which at eight sites and a 12–35s dwell is roughly three minutes per profile. Every profile gets a row whether or not it worked; a dead proxy on one does not cost the rest. Send `planId` **or** the options inline, never both — a plan run with fields on top matches neither the plan you can see nor the body you sent.

#### Body

| Field | Type | What it is |
| --- | --- | --- |
| `profileIds`required | `string[]` | Which profiles to warm. `ids` is accepted as well. |
| `planId` | `string` | A saved plan. Omit to send options inline. |
| `…` | `Partial<WarmupOptions>` | Inline options, when no `planId` is given. |

#### Returns

`{ total, results: WarmupBatchResult[] }` — one row per profile with `ok`, `error`, `sitesVisited`, `cookies` and `seconds`.

#### Errors

- 400 — `profileIds` is missing or is not an array.
- 400 — `planId` sent together with options.
- 404 — no plan with that id.

## [Stop a batch](#warmup-cancel-all)

POST`/api/v1/warmup/cancel`

Stops the profile that is warming up and every one still queued behind it. The profile in flight finishes its page and closes cleanly, so the cookies it collected are kept.

#### Returns

`{ cancelled: true }`

## Run the API on your own profiles

The REST API and the MCP server are part of Pro: $49 a month, with the first 14 days free. Free has every browser feature and no API key.

Mosaic is a desktop app

Email yourself the link and open it on your computer.
