Delivered Accounts

Delivered Accounts – Credentials & Verification Codes

Manage delivered TokPortal account metadata via API, then use the versioned POST reveal flow for credentials or verification codes.

Accounts (Delivered)

Once a bundle is accepted and the account manager creates the social media account, it becomes a saved account (also called a delivered account). Its non-secret metadata is available through account GET endpoints. Credentials and verification codes are available only through the versioned POST reveal endpoints described below.

Accounts are mostly read-only via the API. You can list and view account metadata without revealing credentials. Credential or verification-code access requires the irreversible versioned POST flow and its workspace-effective price. Two order-style actions exist on delivered accounts: profile edit requests and advanced warming rewarms.

DANGER: Credential access permanently detaches the account POST /accounts/:id/reveal-credentials and POST /accounts/:id/verification-code are the same reveal event. The saved account's creation timestamp permanently selects its policy against the immutable production cutoff. A pre-cutoff account keeps the prior 0-credit policy. An account created at or after the cutoff costs 150 credits unless an admin-approved Account Owning Fee agreement applies.

For an account created at or after the cutoff, the 150-credit or approved Account Owning reveal permanently ends TokPortal Coverage. It cannot receive new tasks, use managed analytics refresh, or return to Coverage. TokPortal provides no support, modification, replacement, ban protection, refund, credit restoration, or continued account availability after that reveal. Merely displaying credentials or retrieving a code is sufficient; an attempted login is not required. A pre-cutoff account instead keeps prior-policy task access but loses support and ban coverage after access.

For a new-policy account, the first request returns HTTP 428 with the exact disclosure and policy_version. Nothing is debited or revealed at that stage. To continue, resend acknowledge_support_forfeit: true and the exact returned policy_version. Acceptance, debit, reveal and TokPortal Coverage shutdown commit atomically and are recorded against the account. A stale nonempty policy version returns 409 CREDENTIAL_REVEAL_QUOTE_CHANGED without a debit or reveal. Fetch and display the new preview before asking for fresh confirmation. Pre-cutoff accounts retain the prior API contract and do not require the new versioned body.

Do not send Idempotency-Key to either reveal endpoint. Their responses contain secrets, so TokPortal rejects the header before execution with 400 IDEMPOTENCY_KEY_NOT_ALLOWED_FOR_SENSITIVE_RESPONSE. If a transport failure makes an accepted reveal uncertain, retry the same accepted request without that header. The account-level atomic reveal marker prevents a second first-reveal charge. Treat every successful response as sensitive and never log its credential or verification-code fields.

Metadata-only endpoints such as GET /accounts, GET /accounts/:id and GET /accounts/:id/bundles do not trigger reveal.

Account Owning Fee activation is never automatic. A workspace becomes eligible to request it after reaching 25 live accounts with at least 25 percent revealed, but TokPortal admin approval is required. While approval is pending, the 150-credit reveal remains available. After approval, revealing an account activates or uses the stored agreement rate instead of the one-time credit charge: $10 per account every 30 days for an existing legacy agreement or $15 for a new agreement.

INFO: Historical prior-policy reveals remain grandfathered A saved account created before the immutable cutoff is not converted into a terminal managed reveal. Its support and ban protection end after access, but its existing TokPortal task access is preserved. The account.revealed webhook reports management_ended: false for that prior-policy case. A first reveal for an account created at or after the cutoff reports management_ended: true and applies the permanent detachment rules above.

TokPortal Coverage

TokPortal Coverage grandfathering uses the authoritative cutover timestamp recorded by the production migration. Every TikTok or Instagram saved account that already exists at that instant remains permanently grandfathered. A saved account created afterwards receives one Coverage record when its account listing first reaches in_review, unless its creation response marks it contractually exempt.

  • Coverage belongs to saved_account_id, never to a bundle.
  • Each covered account occupies a limited slot on a real manager phone. The recurring period reserves ongoing device and manager capacity even between tasks.
  • Creation checkout charges the standard 32-credit setup price or the exact price returned by an active contract_bundle_allowance. No Coverage period is charged at checkout. For an eligible saved account created after the production cutover, the first 30 days of Coverage are included from review submission. A contractual allowance can mark the resulting account Coverage-exempt.
  • Each later 30-day period costs 25 credits independently of task volume or bundle state.
  • The first 25-credit debit happens on day 30 and covers the next 30 days.
  • pending_setup and published bundles cannot activate Coverage because no account has been submitted yet.
  • Bundle completion, cancellation, and 60-day inactivity archiving never stop account-level Coverage.
  • Multiple bundles on the same saved account still produce one Coverage record and one periodic charge.
  • Insufficient credits make Coverage lapsed and block new and queued task execution.
  • A client can pause coverage manually. The account immediately loses all task access, but the current included or paid period remains recorded and is not refunded or extended.
  • Reactivation before that period's original end date costs 0 credits and resumes benefits through the same end date. After a renewal boundary, reactivation charges exactly 25 credits for each unpaid 30-day period. It never adds a second overlapping period.
  • In API payloads, cancelled is this recoverable client-initiated pause. ended_cancelled is a legacy terminal state and is never produced by completing or cancelling a bundle.
  • On a lapse or manual pause, unposted videos return to a configured state, task execution and payout are blocked, and reactivation restores work with adjusted future publish dates. Work already submitted for review is frozen instead of duplicated.
  • TokPortal Coverage periods are never refunded.
  • A confirmed banned-account refund or credit-restoration resolution changes Coverage to terminal ended_ban; no future renewal or reactivation is possible.
  • Reveal ends Coverage permanently as ended_revealed.

An eligible ban restoration requires Coverage to have been active when the ban occurred, no prior credential or verification-code reveal, and a claim opened within 15 days that satisfies the Ban and Replacement Policy. It can restore the initial account setup, warming and unused video-slot credits. Used or published work and Coverage periods are not restored. The restored credit lot expires 60 days after restoration.

managed_subscription remains the stable technical API field for TokPortal Coverage. For a TikTok or Instagram saved account that already existed at the recorded production cutover, null means the account is grandfathered. Do not treat every null or every MANAGED_SUBSCRIPTION_NOT_FOUND response as proof of grandfathering: YouTube accounts, accounts that are not Coverage-eligible, and accounts without a Coverage record can also have no subscription. Use the account platform, saved-account creation timestamp, production cutover returned by the API, and delivery state together.

Use GET /accounts/:id/managed-subscription for the dedicated state, POST /accounts/:id/managed-subscription/cancel to pause coverage, and POST /accounts/:id/managed-subscription/reactivate to confirm the latest disclosed amount and resume work. Copy reactivation_credits, current_period_end, and lock_version from the latest GET response into expected_credits, expected_current_period_end, and expected_lock_version in the reactivation request. A zero-credit quote is valid. TokPortal rejects a stale quote without changing periods, resuming tasks, or debiting credits.

Treat the returned effective status, task_access, and period_expired values as authoritative. Exactly at current_period_end, effective status can already be lapsed while the compatibility field recorded_status still says included or active for a few minutes until the renewal worker persists the transition. Never continue task execution based only on recorded_status.

See TokPortal Coverage for the client-facing explanation of the service and its guarantees.

Coverage state and next action

statustask_accessMeaningClient action
includedallowedFirst 30 days are included.No payment is due.
activeallowedCurrent 30-day period is paid.No action is required.
lapsedblockedA renewal could not be paid. Queued work is withheld.Fetch a fresh quote, then reactivate.
cancelledblockedThe client paused Coverage. The current paid or included period is not refunded.Fetch a fresh quote, then reactivate. The quote can be 0 credits before the current period ends.
ended_banblockedCoverage ended after a confirmed ban resolution.Terminal. It cannot be reactivated.
ended_revealedblockedCredentials or a verification code were revealed and the account was detached.Terminal. It cannot be reactivated.
unrecoverable or ended_cancelledblockedLegacy terminal state.Contact support only if the state is unexpected. Do not retry payment.

Read the current state before presenting any payment confirmation:

curl -X GET \
  https://app.tokportal.com/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c/managed-subscription \
  -H "X-API-Key: sk_xxx"

For lapsed or cancelled, use the exact snapshot from that response:

{
  "data": {
    "status": "cancelled",
    "current_period_end": "2026-09-09T11:00:00.000Z",
    "lock_version": 4,
    "unpaid_periods": 0,
    "reactivation_credits": 0,
    "reactivation_quote": {
      "credits": 0,
      "unpaid_periods": 0,
      "current_period_end": "2026-09-09T11:00:00.000Z",
      "lock_version": 4,
      "quoted_at": "2026-08-18T10:15:00.000Z"
    },
    "task_access": "blocked"
  }
}

Then confirm that exact quote. A zero-credit confirmation is intentional and still required to resume work:

curl -X POST \
  https://app.tokportal.com/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c/managed-subscription/reactivate \
  -H "X-API-Key: sk_xxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: coverage-reactivate-9f3a7b2e-v4" \
  -d '{
    "expected_credits": 0,
    "expected_current_period_end": "2026-09-09T11:00:00.000Z",
    "expected_lock_version": 4
  }'
  • On 409 QUOTE_CHANGED, discard the old quote, call the GET endpoint again, show the new amount, and retry with a new idempotency key only after confirmation.
  • On 402 INSUFFICIENT_CREDITS, use details.required, details.available, and details.missing to show the exact top-up needed. Fetch a new quote after the wallet is funded.
  • On a network error or 503 IDEMPOTENCY_UNAVAILABLE, retry the exact same body with the same idempotency key. Never change the body while reusing a key.
  • On a persistent 409 IDEMPOTENCY_KEY_IN_PROGRESS, stop automated retries and do not switch keys. Ask TokPortal support to reconcile the request and financial logs; an uncertain processing claim remains fail-closed and never expires into a second debit.
  • The successful response contains credits_charged, the resumed task summary, the new period, and the new lock_version. Refresh your local account state from that response or a new GET.

For example, an account that missed two 30-day boundaries costs 50 credits to reactivate at the standard 25-credit rate, not 75. The quote contains only unpaid periods and never adds an overlapping extra period.

To pause Coverage, call the cancel endpoint with an idempotency key. The action is immediate, never refunds or extends the current period, and is safe to repeat:

curl -X POST \
  https://app.tokportal.com/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c/managed-subscription/cancel \
  -H "X-API-Key: sk_xxx" \
  -H "Idempotency-Key: coverage-pause-9f3a7b2e-v4"

List Accounts

GET /accounts

Returns a paginated list of your delivered accounts. Use query parameters to filter results.

ParameterTypeDescription
platformstringFilter by platform: tiktok, instagram, or youtube. YouTube accounts are delivered through a separate, non-API flow — they cannot be ordered through the API and are outside TokPortal Coverage — but existing ones are listed here.
countrystring(Optional) Filter by country code or TokPortal canonical country code (e.g., US, USA, FR, UK).
bannedboolean(Optional) true returns only banned accounts (validated or detected — matching the banned response field); false returns only non-banned accounts.
pageintegerPage number (default: 1).
per_pageintegerResults per page (default: 25, max: 100).

TIP: tip The country parameter is optional. If you just need all your accounts, omit it — or filter by platform only.

curl -X GET "https://app.tokportal.com/api/ext/accounts?platform=tiktok" \
  -H "X-API-Key: sk_xxx"

Response:

{
  "data": [
    {
      "id": "9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c",
      "platform": "tiktok",
      "username": "coolcreator99",
      "visible_name": "Cool Creator",
      "biography": "Lifestyle & trends | DM for collabs",
      "profile_picture_url": "https://pub-xxx.r2.dev/profile-pictures/pfp-abc123.jpg",
      "country": "US",
      "link_in_bio": "https://linktr.ee/coolcreator99",
      "profile_url": "https://www.tiktok.com/@coolcreator99",
      "created_at": "2026-01-10T08:00:00Z",
      "updated_at": "2026-02-05T12:30:00Z"
    },
    {
      "id": "b2c3d4e5-6f7a-8b9c-0d1e-2f3a4b5c6d7e",
      "platform": "tiktok",
      "username": "trendwatcher22",
      "visible_name": "Trend Watcher",
      "biography": "Following the latest trends",
      "profile_picture_url": null,
      "country": "US",
      "link_in_bio": null,
      "profile_url": "https://www.tiktok.com/@trendwatcher22",
      "created_at": "2026-01-12T10:30:00Z",
      "updated_at": "2026-01-12T10:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 2,
    "total_pages": 1
  }
}

List Response Fields

FieldTypeDescription
idstring (UUID)Unique account identifier.
platformstringtiktok, instagram, or youtube.
usernamestringPlatform username.
visible_namestringDisplay name on the platform.
biographystringAccount bio text.
profile_picture_urlstring | nullURL to the profile picture.
countrystringCountry code returned by TokPortal.
link_in_biostring | nullLink in bio URL.
profile_urlstringDirect URL to the social media profile.
bannedbooleantrue when the account was banned by the platform (validated ban report). Banned accounts stay listed.
banobject | nullnull unless banned. On the list response: { reason, banned_at }. The detail response adds appeal_status and screenshot_url — see Ban info.
ban_appealobject | nullLatest validated ban report across the whole lifecycle — including appeal_pending (platform appeal filed, account unavailable but not yet banned) and the staff resolution (refund / remake / no_remake). { id, status, reported_at, decided_at, resolution }. See Bans & Appeals.
created_atstringISO 8601 creation timestamp.
updated_atstringISO 8601 last-updated timestamp.

Note: The list response does not include a status field.

Get Account Details

GET /accounts/:id

Returns account metadata. Credentials are not returned by this endpoint. A plain metadata fetch does not trigger credential reveal.

curl -X GET https://app.tokportal.com/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c \
  -H "X-API-Key: sk_xxx"

Response:

{
  "data": {
    "id": "9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c",
    "platform": "tiktok",
    "username": "coolcreator99",
    "visible_name": "Cool Creator",
    "biography": "Lifestyle & trends | DM for collabs",
    "profile_picture_url": "https://pub-xxx.r2.dev/profile-pictures/pfp-abc123.jpg",
    "country": "US",
    "link_in_bio": "https://linktr.ee/coolcreator99",
    "profile_url": "https://www.tiktok.com/@coolcreator99",
    "banned": false,
    "ban": null,
    "created_at": "2026-01-10T08:00:00Z",
    "updated_at": "2026-02-05T12:30:00Z",
    "bundle_id": "bnd_abc123",
    "external_ref": "campaign-42",
    "reveal_endpoint": "/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c/reveal-credentials",
    "verification_code_endpoint": "/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c/verification-code",
    "managed_subscription": {
      "id": "4ba2337a-c81b-4d0d-b67a-64b19dbe5d88",
      "saved_account_id": "9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c",
      "status": "active",
      "current_period_start": "2026-09-09T08:00:00Z",
      "current_period_end": "2026-10-09T08:00:00Z",
      "period_rate_credits": 25,
      "lock_version": 4,
      "unpaid_periods": 0,
      "reactivation_credits": null,
      "quote_generated_at": "2026-09-12T10:15:00Z",
      "reactivation_quote": null,
      "task_access": "allowed"
    },
    "remade": {
      "was_remade": true,
      "remade_count": 1,
      "old_username": "coolcreator9",
      "remade_at": "2026-02-04T09:15:00Z"
    }
  }
}

Additional Detail Fields

FieldTypeDescription
bundle_idstring (UUID) | nullThe bundle this account belongs to. Stable across remakes — prefer it (or external_ref) over the account id when tracking an account that may be replaced. null if it cannot be resolved.
external_refstring | nullThe external_ref set on the owning bundle. Also stable across remakes. null when none was set or it cannot be resolved.
reveal_endpointstringPath to the irreversible credential reveal endpoint.
verification_code_endpointstringPath to POST to in order to retrieve the latest verification code.
managed_subscriptionobject | nullTokPortal Coverage state for this saved account. For a TikTok or Instagram saved account that already existed at the production cutover, null means grandfathered. It can also be null for an ineligible platform or when no Coverage record exists. A paused value includes the exact reactivation_credits, current_period_end, and lock_version snapshot required for reactivation; a zero-credit quote is valid.
remadeobjectWhether this account was rebuilt (remade) after the previous account was banned or lost. See Remake info below.
banned / banboolean / object | nullWhether the account is banned, with the full ban details. See Ban info below.

Note: The detail response does not include status. The list response (GET /accounts) does not include bundle_id, external_ref, or remade.

Ban info

When a ban is validated (the manager reported it with no appeal available, the platform refused the appeal, or staff confirmed it), the account is marked banned but stays visible on GET /accounts and GET /accounts/:id:

{
  "banned": true,
  "ban": {
    "reason": "Community guidelines violation notice shown in-app",
    "banned_at": "2026-07-06T19:13:43Z",
    "appeal_status": "no_appeal_banned",
    "screenshot_url": "https://...signed-url..."
  }
}
FieldTypeDescription
reasonstring | nullBan reason reported by the manager or staff.
banned_atstring (ISO 8601)When the ban was validated.
appeal_statusstring | nullno_appeal_banned (no platform appeal was available) or appeal_refused (the platform refused the appeal). Detail response only.
screenshot_urlstring | nullSigned URL (valid 7 days) to the ban evidence screenshot, when one was provided. Detail response only.

A validated ban also cancels every active bundle and order on the account (those bundles return status: "cancelled" with a cancelled_reason) and stops the Account Owning Fee if one was active. Subscribe to the account.banned and bundle.cancelled webhooks to detect bans without polling. A ban does not automatically remake the account — if a remake follows, account.remade fires on the same bundle_id.

For the full lifecycle — including the pending-appeal limbo before a ban is validated and the staff refund / remake / no-remake decision — poll GET /account-bans or subscribe to the ban lifecycle webhooks (account.ban_appeal.submitted, account.ban_appeal.resolved, account.banned, account.ban_resolution.decided).

Remake info

When an account is banned or lost, TokPortal can remake it: the same bundle is republished and a fresh social account is created (usually under a slightly altered username). The remade object lets you detect this and recover the previous handle.

CAUTION: caution A remake replaces the saved account: the account id you currently hold is removed and a new one is created, so requests against the old account id will return 404. The bundle_id and external_ref (above) stay stable across remakes — use them as your correlation key, and subscribe to the account.remade webhook to be notified the moment it happens.

FieldTypeDescription
was_remadebooleantrue if this account was remade at least once, otherwise false.
remade_countintegerNumber of times the underlying bundle has been remade (0 when never remade).
old_usernamestring | nullThe previous username, captured at the time of the most recent remake. null if unknown or never remade.
remade_atstring (ISO 8601) | nullTimestamp of the most recent remake. null if never remade.

Note: remade is always present on the detail response. When the account was never remade it returns { "was_remade": false, "remade_count": 0, "old_username": null, "remade_at": null }. It is not included in the list response (GET /accounts).

List Bundles for an Account

GET /accounts/:id/bundles

Returns all bundles associated with a delivered account. This includes bundles where the account was originally created (account_and_videos) and any videos_only bundles linked to this account.

Each bundle includes a video slot summary, making it easy to find bundles with available posting slots.

ParameterTypeDescription
statusstring(Optional) Filter by bundle status: pending_setup, published, accepted, completed.
pageintegerPage number (default: 1).
per_pageintegerResults per page (default: 25, max: 100).
curl -X GET "https://app.tokportal.com/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c/bundles?status=accepted" \
  -H "X-API-Key: sk_xxx"

Response:

{
  "data": [
    {
      "id": "b1a2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
      "title": "US TikTok Campaign Q1",
      "bundle_type": "account_and_videos",
      "platform": "tiktok",
      "country": "USA",
      "status": "accepted",
      "videos_quantity": 10,
      "edits_quantity": 2,
      "used_edits": 1,
      "credit_cost": 50,
      "external_ref": "campaign-q1-2026",
      "existing_account_id": null,
      "auto_finalize_videos": true,
      "wants_niche_warming": false,
      "wants_deep_warming": false,
      "wants_moderation": false,
      "created_at": "2026-01-15T10:00:00Z",
      "updated_at": "2026-02-01T14:30:00Z",
      "videos": {
        "total": 10,
        "pending": 3,
        "configured": 2,
        "published": 5,
        "accepted": 0,
        "finalized": 0
      }
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 25,
    "total": 1,
    "total_pages": 1
  }
}

wants_niche_warming and wants_deep_warming are legacy — kept only for accounts being re-created after a refund; use Advanced Niche Warming (wants_advanced_warming).

TIP: Finding available posting slots Use the videos.pending count to identify bundles that have empty video slots ready to be configured. This is especially useful when managing many bundles for the same account — you can quickly find where to schedule your next video without paginating through all bundles.

Reveal Credentials

POST /accounts/:id/reveal-credentials

Call the endpoint once without acceptance to obtain the current versioned disclosure. It returns HTTP 428 and does not reveal or debit anything. Then explicitly accept that exact version:

curl -X POST \
  https://app.tokportal.com/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c/reveal-credentials \
  -H "X-API-Key: sk_xxx"

The preview response is intentionally an error so an unattended integration cannot accept legal and billing terms by accident:

{
  "error": {
    "code": "CREDENTIALS_ACKNOWLEDGMENT_REQUIRED",
    "message": "The current credential-reveal terms must be accepted explicitly.",
    "details": {
      "policy_version": "managed-credential-reveal-v1",
      "disclosure": "Review the full disclosure returned by the API.",
      "acknowledgment": "Review the exact acknowledgment returned by the API."
    }
  }
}

Display the complete details.disclosure and details.acknowledgment values returned by the server. Do not hard-code or shorten them. After the account owner confirms, resend the exact details.policy_version:

curl -X POST https://app.tokportal.com/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c/reveal-credentials \
  -H "X-API-Key: sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "acknowledge_support_forfeit": true,
    "policy_version": "VERSION_RETURNED_BY_428"
  }'

The response includes credits_charged, acceptance_id, policy_version, revealed_at and the credentials. A pre-cutoff account keeps the prior 0-credit policy. For an account created at or after the cutoff, the 150-credit debit applies once and is final and non-refundable unless an admin-approved Account Owning Fee agreement applies. After approval, reveal activates or uses the stored $10 legacy or $15 new per-30-day rate instead of the one-time credit charge. A successful new-policy reveal permanently detaches the account from TokPortal: it becomes read-only and cannot receive any new or resumed platform task. TokPortal Coverage, analytics updates, support, ban protection, replacement, refunds, compensation and credit restoration all end. TokPortal is not responsible for later access, performance, reach, security, restrictions or bans. A detached account cannot be restored to TokPortal Coverage.

Do not send Idempotency-Key. If a stale accepted policy returns 409 CREDENTIAL_REVEAL_QUOTE_CHANGED, no debit or reveal occurred. Request the no-body preview again, display the changed terms and price, then continue only after new account-owner confirmation.

Retrieve Verification Code

POST /accounts/:id/verification-code

Retrieves the most recent 6-digit verification code from the account's TokMail inbox.

DANGER: danger Retrieving a verification code is exactly equivalent to revealing credentials. It costs the account-specific effective reveal price on first access and, when completed through the new-policy 150-credit or Account Owning path, permanently detaches the account as described above. A pre-cutoff account keeps the prior 0-credit contract.

How it works:

  1. Trigger a verification code from the platform (e.g., request a login code from TikTok or Instagram).
  2. Wait a few seconds for the email to arrive.
  3. Call this endpoint to retrieve the code from the TokMail inbox.

First request the same no-body policy preview used by credential reveal:

curl -X POST \
  https://app.tokportal.com/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c/verification-code \
  -H "X-API-Key: sk_xxx"

If the account has not already been revealed, this returns 428 CREDENTIALS_ACKNOWLEDGMENT_REQUIRED with the current disclosure and policy version. Only after explicit confirmation should the client send the accepted request below.

curl -X POST https://app.tokportal.com/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c/verification-code \
  -H "X-API-Key: sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "acknowledge_support_forfeit": true,
    "policy_version": "VERSION_RETURNED_BY_428"
  }'

Response:

{
  "data": {
    "account_id": "9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c",
    "verification_code": "482937",
    "source": "email"
  }
}

Response Fields

FieldTypeDescription
account_idstring (UUID)The account this code belongs to.
verification_codestringThe 6-digit verification code.
sourcestring"email" (fetched from inbox) or "cached" (returned from cache).

Error — no code found:

{
  "error": {
    "code": "VERIFICATION_CODE_NOT_FOUND",
    "message": "No verification code found in the inbox. Make sure you triggered the code from the platform first and wait a few seconds before retrying."
  }
}

Tip: If you receive a VERIFICATION_CODE_NOT_FOUND error, wait 5-10 seconds and retry. Email delivery can take a moment.

To run a delivered video as a native ad, request a TikTok Spark Code for that specific finalized video — see Ad Code Request.

To re-warm a delivered account with search-term based Advanced Warming (5 credits per term at the standard rate, screen-recorded proof and verified engagement reports), call POST /accounts/{id}/rewarm while the account has active Coverage or grandfathering, a routable active manager, and a non-cancelled support order. Completed bundles remain eligible. See Advanced Warming.