Source: https://developers.tokportal.com/credits/
Markdown: https://developers.tokportal.com/credits.md

# Credits & Pricing

TokPortal uses a **credit-based system** as its unified currency. The same credit balance is shared between the API and the web UI — there is no separate API billing.

> **TIP: Check the price before you pay it**
> Credits are debited when a bundle is **created**, not when it is published, and there is no cancellation or refund path. Add `X-TokPortal-Dry-Run: true` to any write and it is simulated instead: the same validation, the same errors, and `credits_would_charge` with the real price for your workspace — nothing created, nothing charged. See [Sandbox (dry run)](https://developers.tokportal.com/sandbox).

## Credit Costs

| Operation                                                   | Cost                                                                                                                                                                                                                                                                                                                              |
| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TikTok or Instagram account setup                           | 32 credits, unless `contract_bundle_allowance` returns a workspace-specific price                                                                                                                                                                                                                                                 |
| YouTube account setup                                       | 100 credits — **not orderable through the API.** The price is real and `GET /credit-costs` returns it, but `POST /bundles` rejects a YouTube bundle with `YOUTUBE_DELAYED`; YouTube accounts are delivered through a separate flow arranged with the team. YouTube is outside TokPortal Coverage                                  |
| Video slot                                                  | 2 credits per video                                                                                                                                                                                                                                                                                                               |
| Advanced Niche Warming                                      | 5 credits **per niche target** — never per day. Targets are bought 3 to 30 at a time in multiples of 3, so the minimum order is 15 credits. Requires `wants_advanced_warming: true` in the same body, otherwise the call is refused and nothing is charged. Unless `contract_bundle_allowance` returns a workspace-specific price |
| TokPortal Coverage                                          | 25 credits every 30 days per eligible saved account; first period included                                                                                                                                                                                                                                                        |
| Credential or verification-code reveal (Account Owning Fee) | Account-specific: 0 credits under the prior policy for a saved account created before the immutable cutoff; 150 credits for an account created at or after it unless an admin-approved Account Owning Fee agreement applies                                                                                                       |
| Video editing                                               | 3 credits per edit slot                                                                                                                                                                                                                                                                                                           |
| Comments API task (comment or reply)                        | 1 credit per task; the former per-bundle moderation add-on is unavailable                                                                                                                                                                                                                                                         |
| Sound volume control                                        | 1 credit per video                                                                                                                                                                                                                                                                                                                |
| Story repost link (`story_repost_url`)                      | 1 credit per story, charged once                                                                                                                                                                                                                                                                                                  |
| Instant repost as story (`instant_repost_as_story`)         | 1 credit per video, charged once                                                                                                                                                                                                                                                                                                  |
| Ad code (TikTok Spark Code / Instagram Partner Code)        | 7 credits per finalized video                                                                                                                                                                                                                                                                                                     |
| Account edit request                                        | 8 credits per request                                                                                                                                                                                                                                                                                                             |

**Advanced Niche Warming is the only warming TokPortal sells.** The `niche_warming` and `deep_warming` entries you may still see in a `GET /credit-costs` payload are legacy: they are kept only for accounts being re-created after a refund, they are not part of the current offer, and new deep-warming orders are rejected outright with `DEEP_WARMING_DEPRECATED`. Do not price a new order from them.

### Current pricing and the August 2026 cutover

Every price in the table above is the **current standard rate**. Older material — earlier newsletters, the marketing site, or a cached copy of these docs — may still show the pre-transition rates (25 credits per account setup, 3 or 4 credits per warming target, a 25-credit "comment moderation" add-on). Those rates are historical: only `GET /credit-costs` and the checkout quote are authoritative.

Two figures are easy to confuse because both are 25 credits: the **recurring 25 credits every 30 days is TokPortal Coverage**, charged per eligible saved account. The old per-bundle "comment moderation" add-on has been removed entirely — comment work is now billed per task at 1 credit through the [Comments API](https://developers.tokportal.com/comments-overview), with no monthly component.

- The production migration records one authoritative pricing cutover timestamp. `GET /credit-costs` returns it in `pricing_transition`; clients must not hard-code the deployment time. At the time of writing it is `2026-08-12T08:02:34.814507Z`.
- Workspaces that had not bought credits before that instant moved to the current rates immediately. Workspaces that had already paid for credits kept the previous rates until **August 14, 2026 at 11:00 UTC**. Both grace windows are now closed: every workspace pays 32 credits for account setup and 5 credits per Advanced Warming target, except where the live API returns a contractual allowance in `contract_bundle_allowance`.
- TokPortal Coverage grandfathering is account-specific and still uses the recorded production cutover. Every TikTok or Instagram saved account that already existed at that instant remains permanently grandfathered. A saved account created after it is Coverage-eligible unless its creation response marks it contractually exempt.
- Credential and verification-code reveal policy is also selected permanently from the saved account's creation timestamp, not the workspace transition. A pre-cutoff saved account keeps the prior 0-credit access policy; a saved account created at or after the cutoff uses the 150-credit managed policy unless Account Owning is already approved.
- The server always computes the effective workspace and account price before debit.

> **INFO: Grandfathered accounts keep their old terms — permanently**
>
> Grandfathering is decided **per saved account**, from that account's `created_at`, against the immutable production cutover (`pricing_transition.managed_account_eligibility_at` in `GET /credit-costs`, currently `2026-08-12T08:02:34.814507Z`).
>
> | Saved account created                                             | TokPortal Coverage                                                                                           | Credential / verification-code reveal                                                                                                                       |
> | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
> | **Before the cutover** (accounts delivered up to August 12, 2026) | Never charged. `managed_subscription` is `null` and stays `null`; the account keeps full task access forever | Prior policy, **0 credits**. The reveal is still irreversible and ends support plus ban coverage, but the account is not detached and keeps its task access |
> | **At or after the cutover**                                       | 25 credits every 30 days, first 30-day period included                                                       | Managed policy, **150 credits**, or the approved Account Owning Fee rate. Reveal permanently detaches the account and ends Coverage                         |
>
> Grandfathering follows the account, not the workspace: a long-standing client who creates a new account today pays the current rates on that new account while their older accounts stay grandfathered. Nothing you can send in a request changes an account's cohort, and there is no expiry date on a grandfathered account.
>
> Workspace **action prices** (account setup, Advanced Warming) are a separate axis and are no longer grandfathered at all — both transition windows closed on August 14, 2026.

### TokPortal Coverage

TokPortal Coverage is attached to the **saved account**, never to a bundle. One account has at most one Coverage record. Creating several bundles for the same account does not create or charge another period.

Each covered account reserves a limited slot on a real manager phone. The recurring charge therefore covers ongoing hardware and manager capacity, not only the moments when a task is actively running. See [TokPortal Coverage](https://www.tokportal.com/managed-account-fee) for the client-facing service explanation.

Bundle creation checkout charges 32 setup credits, or the exact account price returned in an active `contract_bundle_allowance`. No Coverage period is charged at checkout. For a non-grandfathered, non-exempt saved account created after the production cutover, TokPortal Coverage becomes active when the manager submits it for client review. The first 30 days are included, so the first 25-credit Coverage debit occurs on day 30 and pays for the following 30 days. A TikTok or Instagram saved account that already existed at the cutover remains grandfathered permanently. Every successful renewal is written to the credit transaction history. A bundle that is still in `pending_setup` or only `published` cannot start this clock.

Coverage is unique per `saved_account_id`, not per bundle. Additional bundles never duplicate the charge, and completed, cancelled, or inactive bundles do not stop Coverage. If there are not enough credits at a renewal boundary, Coverage lapses and all tasks are paused. A client may also pause it manually. Pausing stops benefits immediately but does not refund or extend the current period. Reactivation before the current paid or included period expires is free and resumes benefits only until its original end date. After that date, reactivation atomically pays exactly the unpaid 30-day periods, with no extra overlapping period, then resumes withheld work with updated scheduling. Coverage periods are never refunded.

A current managed-policy credential or verification-code reveal ends Coverage permanently. A historical prior-policy reveal keeps its grandfathered task-access behavior. Coverage also ends after staff confirms a banned-account resolution that restores or refunds the eligible account, warming, and unused-video credits. Terminal Coverage does not renew and cannot be reactivated.

For a confirmed eligible platform ban, TokPortal can restore the initial account setup, warming and unused video-slot credits. Coverage must have been active when the ban occurred, the account must never have been revealed, and the claim must be opened within 15 days and satisfy the [Ban and Replacement Policy](https://www.tokportal.com/ban-and-replacement-policy). Restored credits expire 60 days after restoration. Used or published work and the Coverage period itself are not restored.

### Credential reveal and Owning Fee

The first password reveal or verification-code retrieval is one irreversible reveal event. A saved account created before the immutable production cutoff keeps the prior policy at 0 credits: support and ban coverage end, but the account is not detached and existing task access remains. A saved account created at or after the cutoff costs 150 credits unless an admin-approved Account Owning Fee agreement applies. For a new-policy account, the API first returns HTTP 428 with the exact current policy and `policy_version`; the caller must resend both `acknowledge_support_forfeit: true` and that exact version. A stale nonempty version returns `409 CREDENTIAL_REVEAL_QUOTE_CHANGED` without a debit or reveal, so clients must fetch and show the changed policy before requesting fresh confirmation.

For a new-policy account, reveal permanently detaches the account from TokPortal Coverage. The account can no longer receive tasks or analytics refreshes on TokPortal, and no support, replacement, ban protection, refund, credit restoration, compensation or modification is provided. The reveal debit and Coverage shutdown are atomic. Do not send `Idempotency-Key` because the response contains secrets; TokPortal rejects it before execution. The prior policy for pre-cutoff saved accounts remains grandfathered: support and ban protection end after access, while existing task access remains and the account is not detached.

Account Owning Fee activation requires TokPortal admin approval. Reaching the threshold of 25 live accounts with at least 25 percent revealed creates a pending request and alerts TokPortal. While pending, the client can still use the 150-credit reveal. After approval, revealing an account activates or uses the stored agreement rate instead of the one-time credit charge. Existing legacy agreements remain at $10 per account every 30 days; newly approved agreements use $15.

## How Credits Are Debited

- **Bundle creation:** Credits for account creation, video slots, warming and editing are calculated server-side and debited atomically when the bundle is created. The client never determines the cost; the server computes the total from the bundle configuration. The former per-bundle moderation add-on is unavailable.
- **Comments API tasks:** Each comment or reply task costs 1 credit, debited up front and refunded automatically when it cannot be fulfilled under the Comments API rules.
- **Add video slots** — When you add video slots to an existing bundle, credits are debited immediately.
- **Add edit slots** — When you add edit slots to an existing bundle, credits are debited immediately.
- **Sound volume control** — 1 credit is debited the **first time** `volume_original_sound` or `volume_added_sound` is set on a video. Subsequent updates to the same fields on the same video are free.
- **Refund boundary** - TokPortal Coverage periods are never refunded. Outside a confirmed eligible ban resolution, only unused video slots, eligible unconfigured warming, and the initial account creation charge in an eligible cancellation flow may be refunded. Eligible ban restoration follows the separate scope and 60-day validity described above.

## Endpoints

### Get Credit Balance

```bash
curl -X GET https://app.tokportal.com/api/ext/credits/balance \
  -H "X-API-Key: sk_xxx"
```

```json
{
  "data": {
    "total_credits": 1250,
    "expiring_within_7_days": 0,
    "upcoming_expirations": [
      {
        "amount": 638,
        "expires_at": "2026-06-08T04:47:51.413+00:00",
        "source": "farmer_topup"
      }
    ],
    "last_updated": "2026-05-19T22:42:36.885166+00:00"
  }
}
```

| Field                    | Type           | Description                                                                                                                                  |
| ------------------------ | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `total_credits`          | number         | Current available credit balance.                                                                                                            |
| `expiring_within_7_days` | number         | Sum of credits that will expire in the next 7 days.                                                                                          |
| `upcoming_expirations`   | array          | Credit lots expiring in the next 30 days (sorted by `expires_at` ascending). Each entry has `amount`, `expires_at` (ISO-8601), and `source`. |
| `last_updated`           | string \| null | Timestamp of the last balance update.                                                                                                        |

### Get Credit History

```bash
curl -X GET https://app.tokportal.com/api/ext/credits/history?page=1&per_page=10 \
  -H "X-API-Key: sk_xxx"
```

```json
{
  "data": [
    {
      "id": "txn_abc123",
      "type": "debit",
      "amount": -97,
      "description": "Bundle created: 1 TikTok account, 10 videos, 9 Advanced Niche Warming targets",
      "breakdown": {
        "account_creation": 32,
        "video_slots": 20,
        "advanced_warming": 45
      },
      "balance_after": 1153,
      "created_at": "2025-11-20T14:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 10,
    "total": 47,
    "total_pages": 5
  }
}
```

### Get Credit Costs

Retrieve the current cost table programmatically immediately before creating a bundle. `CUTOVER_TIMESTAMP_FROM_API` stands for the real ISO 8601 timestamp returned by the live endpoint. To keep the example readable, each nested cost object shows only `credits`; the live response also includes its required `description` and `note` fields.

```bash
curl -X GET https://app.tokportal.com/api/ext/credit-costs \
  -H "X-API-Key: sk_xxx"
```

```json
{
  "data": {
    "costs": {
      "account_creation": { "credits": 32 },
      "youtube_account_creation": { "credits": 100 },
      "video_upload": { "credits": 2 },
      "advanced_warming": { "credits": 5 },
      "niche_warming": { "credits": 7, "description": "LEGACY — not offered. Superseded by Advanced Niche Warming (advanced_warming)." },
      "deep_warming": { "credits": 40, "description": "LEGACY — discontinued, new orders are rejected. Superseded by advanced_warming." },
      "video_edit": { "credits": 3 },
      "comment_task": { "credits": 1 },
      "sound_volume": { "credits": 1 },
      "repost_url": { "credits": 1 },
      "ad_code": { "credits": 7 },
      "managed_account_subscription": { "credits": 25 },
      "credential_reveal": { "credits": 150 }
    },
    "workspace_pricing": {
      "cohort": "new_credit_customer",
      "effective_at": "CUTOVER_TIMESTAMP_FROM_API",
      "transition_active": true,
      "tokportal_coverage_eligible_for_new_accounts_now": true
    },
    "contract_bundle_allowance": null,
    "owning_fee": {
      "requires_admin_approval": true,
      "minimum_live_accounts": 25,
      "minimum_reveal_ratio": 0.25,
      "pending_reveal_credits": 150,
      "legacy_usd_per_account_per_30_days": 10,
      "new_agreement_usd_per_account_per_30_days": 15,
      "new_agreement_effective_at": "CUTOVER_TIMESTAMP_FROM_API",
      "note": "Crossing the threshold creates an approval request and never activates Account Owning Fee automatically."
    },
    "pricing_transition": {
      "users_without_paid_credit_purchase_before_transition": {
        "effective_at": "CUTOVER_TIMESTAMP_FROM_API",
        "tokportal_coverage_eligible_for_accounts_created_at_or_after": "CUTOVER_TIMESTAMP_FROM_API",
        "account_creation_credits": 32,
        "advanced_warming_per_term_credits": 5
      },
      "users_with_paid_credit_purchase_before_transition": {
        "effective_at": "2026-08-14T11:00:00.000Z",
        "tokportal_coverage_eligible_for_accounts_created_at_or_after": "CUTOVER_TIMESTAMP_FROM_API",
        "before_effective_at": {
          "account_creation_credits": 25,
          "advanced_warming_per_term_credits": 3
        },
        "after_effective_at": {
          "account_creation_credits": 32,
          "advanced_warming_per_term_credits": 5
        }
      },
      "managed_account_eligibility_at": "CUTOVER_TIMESTAMP_FROM_API",
      "managed_account_eligibility_at_deprecated": false,
      "managed_account_eligibility_note": "Production migration cutover and saved-account grandfathering boundary.",
      "grandfathering": "A TikTok or Instagram saved account that already existed at the production cutover is permanently grandfathered and has no managed_subscription record."
    },
    "examples": {
      "account_only": { "description": "1 TikTok account", "total": 32 },
      "account_with_10_videos": { "description": "1 account + 10 videos", "total": 52 },
      "account_with_10_videos_and_warming": { "description": "1 account + 10 videos + 3 Advanced Niche Warming targets", "total": 67 },
      "account_with_advanced_warming": { "description": "1 account + 12 Advanced Niche Warming targets", "total": 92 },
      "account_with_10_videos_and_advanced_warming": { "description": "1 account + 10 videos + 9 Advanced Niche Warming targets", "total": 97 }
    }
  }
}
```

`contract_bundle_allowance` is `null` for the standard tariff. When present, it is the authoritative workspace-specific contract for qualifying new bundles. It includes the platform, country, supported bundle types, remaining quantity, account setup price, Advanced Warming price and Coverage exemption. A qualifying slot is consumed only when `POST /bundles` or `POST /bundles/bulk` successfully creates the bundle and debits credits. Draft preparation and later publication consume nothing. Bulk allocation is deterministic and atomic. If the allowance changes between quote and checkout, the API returns `409 BUNDLE_PRICING_CHANGED`; nothing is created or charged, and the client must fetch `/credit-costs` again and retry with a new `Idempotency-Key`.

`repost_url` is the cost of adding a [story repost link](https://developers.tokportal.com/configure-videos#story-fields) — charged once, the first time `story_repost_url` is set on a story.

## Cost Breakdown Example

Creating a bundle with the following configuration:

- 1 TikTok account
- 10 video slots
- Advanced Niche Warming with 9 targets (`wants_advanced_warming: true`)
- Video editing enabled (10 edit slots)

| Item                   | Calculation | Cost            |
| ---------------------- | ----------- | --------------- |
| Account creation       | 1 x 32      | 32 credits      |
| Video slots            | 10 x 2      | 20 credits      |
| Advanced Niche Warming | 9 x 5       | 45 credits      |
| Video editing          | 10 x 3      | 30 credits      |
| **Total**              |             | **127 credits** |

If your balance is below the required total, the API returns an `INSUFFICIENT_CREDITS` error with full details:

```json
{
  "error": {
    "code": "INSUFFICIENT_CREDITS",
    "message": "Not enough credits to complete this operation.",
    "details": {
      "required": 127,
      "available": 50,
      "missing": 77,
      "breakdown": {
        "account_creation": 32,
        "video_slots": 20,
        "advanced_warming": 45,
        "edit_slots": 30
      }
    }
  }
}
```
