Source: https://developers.tokportal.com/advanced-warming/
Markdown: https://developers.tokportal.com/advanced-warming.md

# Advanced Niche Warming

**Advanced Niche Warming** is TokPortal's recorded, verified warming product
for TikTok and Instagram accounts. For each **niche target** (a search term
that matches your niche), the account manager:

1. Starts a screen recording **on the account profile** (the account's @handle
   visible — identity proof),
2. searches the target on the platform,
3. watches videos from the results,
4. likes and saves several of them,
5. leaves a comment.

One recording per target, dispatched over **3 calendar days in the manager's
timezone**. Earlier-day tasks remain available until completed. Every recording is verified before it counts, and each
verified target produces a client report (videos watched, likes, saves,
comments, keywords seen, sample videos, proof recording link). When all targets
are verified you receive an aggregated session report.

**Price:** 5 credits per target. Targets are bought in counts of **3 to 30, in
multiples of 3**, so the minimum is 15 credits. The charge is **per target, not
per day**: the 3-day schedule is how the recordings are spread out, not a
billing unit, and a session is never charged more than once. A workspace-specific
`contract_bundle_allowance` can return a different effective rate for a narrowly
defined set of new bundles. The server always returns and debits the effective
rate, and `GET /credit-costs` is the authority — older announcements quoting 3 or
4 credits predate the August 2026 transition.

***

## The flow: buy a count, configure the targets, warming starts

### 1. Buy the target count at bundle creation

Pass `wants_advanced_warming: true` and `advanced_warming_terms_count` on
[`POST /bundles`](https://developers.tokportal.com/create-bundle) (or
[`POST /bundles/bulk`](https://developers.tokportal.com/create-bulk) — the count is per account).
The flag is **mandatory**: it is what is priced and what creates the warming
session, and TokPortal never infers it from the targets alone.

```bash
curl -X POST https://app.tokportal.com/api/ext/bundles \
  -H "X-API-Key: sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "bundle_type": "account_only",
    "platform": "tiktok",
    "country": "US",
    "wants_advanced_warming": true,
    "advanced_warming_terms_count": 9
  }'
```

At the standard rate, 45 credits (9 x 5) are charged at bundle creation checkout.
You don't need the actual targets yet. Publication does not charge them again.

> Prefer to send the targets immediately? Pass `advanced_warming_terms`
> instead of the count — that is a one-shot configuration and skips step 2.
> Send one or the other: a count that disagrees with the list length fails with
> `ADVANCED_WARMING_COUNT_MISMATCH` rather than letting one quantity silently win.

> **WARNING: The opt-in flag is never inferred**
> `advanced_warming_terms` or `advanced_warming_terms_count` sent **without**
> `wants_advanced_warming: true` — absent or explicitly `false` — is rejected with
> `400 ADVANCED_WARMING_FLAG_REQUIRED`. Nothing is charged, no session is created,
> and on `POST /bundles/bulk` the whole batch is refused. The targets are never
> accepted-and-dropped.

### 2. Configure the targets on the bundle

Write the niche targets with `PUT /bundles/{id}/warming-terms`. This dedicated
endpoint stays available at **any account status**, including after the manager
has accepted the mission or submitted the account.

```bash
curl -X PUT https://app.tokportal.com/api/ext/bundles/bnd_abc123/warming-terms \
  -H "X-API-Key: sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "advanced_warming_terms": [
      "healthy meal prep", "high protein recipes", "quick healthy dinner",
      "gym meal ideas", "macro friendly meals", "protein snacks",
      "meal prep sunday", "fitness breakfast", "low calorie desserts"
    ]
  }'
```

Rules:

- The array must contain **exactly** the purchased count of distinct targets,
  each 2-50 characters. Entries are trimmed and compared case-insensitively;
  anything dropped as a duplicate or for its length shrinks the list, and the
  call then fails with `400 ADVANCED_WARMING_TERMS`. TokPortal never quietly
  configures — or bills — fewer targets than you bought. At bundle creation the
  same situation surfaces earlier and more explicitly, as
  `ADVANCED_WARMING_TERMS_REJECTED` with `details.dropped_terms`.
- Configuration is **one-shot** per purchase — afterwards you get
  `409 WARMING_TERMS_ALREADY_SET`.
- `PUT /bundles/{id}/account` still accepts `advanced_warming_terms` while the
  account profile is editable, for backward compatibility. New integrations
  should use `/warming-terms`.
- No targets in mind? Generate them from a niche description with
  `POST /warming/generate-terms` (free).
- The body is a full replace, so an unrecognised field name is rejected with
  `400 UNKNOWN_FIELD` instead of being silently stripped — see
  [Unrecognised fields are refused, not dropped](https://developers.tokportal.com/account-configuration#unrecognised-fields-are-refused-not-dropped).

### 3. Warming starts

- If the account/order is **already active** (existing-account bundle with an
  assigned manager, or a new account already submitted), warming starts the
  moment the targets are configured — the `warming.session_started` webhook
  fires.
- Otherwise it starts automatically when the manager submits the new account
  (or accepts the order for existing-account bundles).

Track progress via `GET /warming-sessions/{id}`,
`GET /accounts/{id}/warming-sessions`, the `advanced_warming` summary on the
bundle account payload (`status`, `terms_total`, `terms_verified`,
`terms_configured`, `started_at`, `completed_at`), and the
`warming.term_verified` / `warming.session_completed` webhooks.

***

## 14-day auto-refund

If you buy a target count but never configure the targets, the purchase does
not linger: **14 days** after creation the warming session is automatically
cancelled and the **full warming cost is refunded** to your credit balance.
The rest of the bundle is unaffected.

Once tasks have been created, they **never expire and are not refunded for
lateness**. Unfinished targets remain open until the manager completes them.
The 14-day refund applies only when the client never configured any targets.

***

## Rewarm a delivered account

Advanced Niche Warming can also be ordered later on an account you already
own via `POST /accounts/{id}/rewarm` — there the `search_terms` are required
in the request (no deferred configuration), and the session starts
immediately. It requires a routable active manager backed by a non-cancelled support order. A completed bundle remains eligible. It also requires active TokPortal Coverage or permanent grandfathering.

If Coverage pauses or lapses after a session starts, unfinished warming tasks are withheld from the manager queue without becoming late. Their durable session state is preserved. Exact-quote Coverage reactivation restores the tasks and scheduling automatically.

***

## Error codes

| Status | Code                              | Meaning                                                                                                                                                                                                                                                                        |
| ------ | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `400`  | `ADVANCED_WARMING_FLAG_REQUIRED`  | `advanced_warming_terms` and/or `advanced_warming_terms_count` was sent without `wants_advanced_warming: true`. Nothing is charged; on `POST /bundles/bulk` the whole batch is refused. `details.supplied_fields` names the fields that triggered it.                          |
| `400`  | `ADVANCED_WARMING_TERMS_REJECTED` | At bundle creation, a term was removed by cleanup — a case-insensitive duplicate, or outside 2-50 characters. `details.dropped_terms` lists them, `details.accepted_terms` shows what survived. The call fails instead of delivering and billing fewer targets than requested. |
| `400`  | `ADVANCED_WARMING_COUNT_MISMATCH` | `advanced_warming_terms` and `advanced_warming_terms_count` state different quantities. Compare `details.terms_count` and `details.requested_count`, then send one or the other.                                                                                               |
| `400`  | `ADVANCED_WARMING_TERMS`          | Invalid targets/count: provide `advanced_warming_terms` (3-30, multiple of 3, entries 2-50 chars) or `advanced_warming_terms_count` (3-30, multiple of 3); at configuration time the targets must match the purchased count exactly.                                           |
| `400`  | `ADVANCED_WARMING_PLATFORM`       | TikTok and Instagram only.                                                                                                                                                                                                                                                     |
| `400`  | `UNKNOWN_FIELD`                   | The body of a full-replace write (`POST /bundles`, `POST /bundles/bulk`, `PUT /bundles/{id}/account`, `PUT /bundles/{id}/warming-terms`) carries a field TokPortal does not recognise. Read `details.unknown_fields` and `details.did_you_mean`.                               |
| `400`  | `WARMING_CONFLICT`                | `wants_advanced_warming` cannot be combined with the legacy `wants_niche_warming` flag, which is kept only for accounts being re-created after a refund. Leave the legacy flag out.                                                                                            |
| `404`  | `WARMING_SESSION_NOT_FOUND`       | No warming session to configure on this bundle.                                                                                                                                                                                                                                |
| `409`  | `WARMING_TERMS_ALREADY_SET`       | Targets already configured (or session already started) — one-shot per purchase.                                                                                                                                                                                               |
| `409`  | `REWARM_ALREADY_ACTIVE`           | A warming session is already active for this account.                                                                                                                                                                                                                          |
| `409`  | `REWARM_NO_ACTIVE_ORDER`          | No routable active manager or non-cancelled support order is available. A completed bundle is valid; a cancelled order is not.                                                                                                                                                 |
| `409`  | `MANAGED_ACCOUNT_TASK_BLOCKED`    | Coverage is inactive or the account is detached, banned, missing Coverage, or otherwise unavailable. No session or debit is created.                                                                                                                                           |
