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-credentialsandPOST /accounts/:id/verification-codeare 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, resendacknowledge_support_forfeit: trueand the exact returnedpolicy_version. Acceptance, debit, reveal and TokPortal Coverage shutdown commit atomically and are recorded against the account. A stale nonempty policy version returns409 CREDENTIAL_REVEAL_QUOTE_CHANGEDwithout 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-Keyto either reveal endpoint. Their responses contain secrets, so TokPortal rejects the header before execution with400 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/:idandGET /accounts/:id/bundlesdo 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.revealedwebhook reportsmanagement_ended: falsefor that prior-policy case. A first reveal for an account created at or after the cutoff reportsmanagement_ended: trueand 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_setupandpublishedbundles 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
lapsedand 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,
cancelledis this recoverable client-initiated pause.ended_cancelledis 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
status | task_access | Meaning | Client action |
|---|---|---|---|
included | allowed | First 30 days are included. | No payment is due. |
active | allowed | Current 30-day period is paid. | No action is required. |
lapsed | blocked | A renewal could not be paid. Queued work is withheld. | Fetch a fresh quote, then reactivate. |
cancelled | blocked | The 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_ban | blocked | Coverage ended after a confirmed ban resolution. | Terminal. It cannot be reactivated. |
ended_revealed | blocked | Credentials or a verification code were revealed and the account was detached. | Terminal. It cannot be reactivated. |
unrecoverable or ended_cancelled | blocked | Legacy 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, usedetails.required,details.available, anddetails.missingto 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 uncertainprocessingclaim 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 newlock_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.
| Parameter | Type | Description |
|---|---|---|
platform | string | Filter 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. |
country | string | (Optional) Filter by country code or TokPortal canonical country code (e.g., US, USA, FR, UK). |
banned | boolean | (Optional) true returns only banned accounts (validated or detected — matching the banned response field); false returns only non-banned accounts. |
page | integer | Page number (default: 1). |
per_page | integer | Results per page (default: 25, max: 100). |
TIP: tip The
countryparameter is optional. If you just need all your accounts, omit it — or filter byplatformonly.
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
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Unique account identifier. |
platform | string | tiktok, instagram, or youtube. |
username | string | Platform username. |
visible_name | string | Display name on the platform. |
biography | string | Account bio text. |
profile_picture_url | string | null | URL to the profile picture. |
country | string | Country code returned by TokPortal. |
link_in_bio | string | null | Link in bio URL. |
profile_url | string | Direct URL to the social media profile. |
banned | boolean | true when the account was banned by the platform (validated ban report). Banned accounts stay listed. |
ban | object | null | null unless banned. On the list response: { reason, banned_at }. The detail response adds appeal_status and screenshot_url — see Ban info. |
ban_appeal | object | null | Latest 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_at | string | ISO 8601 creation timestamp. |
updated_at | string | ISO 8601 last-updated timestamp. |
Note: The list response does not include a
statusfield.
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
| Field | Type | Description |
|---|---|---|
bundle_id | string (UUID) | null | The 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_ref | string | null | The external_ref set on the owning bundle. Also stable across remakes. null when none was set or it cannot be resolved. |
reveal_endpoint | string | Path to the irreversible credential reveal endpoint. |
verification_code_endpoint | string | Path to POST to in order to retrieve the latest verification code. |
managed_subscription | object | null | TokPortal 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. |
remade | object | Whether this account was rebuilt (remade) after the previous account was banned or lost. See Remake info below. |
banned / ban | boolean / object | null | Whether 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 includebundle_id,external_ref, orremade.
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..."
}
}
| Field | Type | Description |
|---|---|---|
reason | string | null | Ban reason reported by the manager or staff. |
banned_at | string (ISO 8601) | When the ban was validated. |
appeal_status | string | null | no_appeal_banned (no platform appeal was available) or appeal_refused (the platform refused the appeal). Detail response only. |
screenshot_url | string | null | Signed 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. Thebundle_idandexternal_ref(above) stay stable across remakes — use them as your correlation key, and subscribe to theaccount.remadewebhook to be notified the moment it happens.
| Field | Type | Description |
|---|---|---|
was_remade | boolean | true if this account was remade at least once, otherwise false. |
remade_count | integer | Number of times the underlying bundle has been remade (0 when never remade). |
old_username | string | null | The previous username, captured at the time of the most recent remake. null if unknown or never remade. |
remade_at | string (ISO 8601) | null | Timestamp of the most recent remake. null if never remade. |
Note:
remadeis 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.
| Parameter | Type | Description |
|---|---|---|
status | string | (Optional) Filter by bundle status: pending_setup, published, accepted, completed. |
page | integer | Page number (default: 1). |
per_page | integer | Results 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.pendingcount 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:
- Trigger a verification code from the platform (e.g., request a login code from TikTok or Instagram).
- Wait a few seconds for the email to arrive.
- 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
| Field | Type | Description |
|---|---|---|
account_id | string (UUID) | The account this code belongs to. |
verification_code | string | The 6-digit verification code. |
source | string | "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_FOUNDerror, wait 5-10 seconds and retry. Email delivery can take a moment.
Related
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.