Comments

Comments – Overview & Lifecycle

Programmatically schedule comments from your delivered TokPortal accounts on third-party social videos. Pricing, lifecycle, and error handling.

Comments

Schedule comments from your delivered TokPortal accounts on third-party social videos. Comments are posted by the account manager assigned to each account, then auto-verified by scraping the target video's comment list.

Each task is either a video target (post a comment under a video) or a comment target (reply to a specific comment under a video — TikTok only). Set this with target_type; see Create → Target types.

POST   /api/ext/comments              Create one or many comment tasks
GET    /api/ext/comments              List your comment tasks (paginated)
GET    /api/ext/comments/{id}         Read one task with full state
DELETE /api/ext/comments/{id}         Cancel a pending task (exact stored-cost refund)
POST   /api/ext/comments/{id}/approve   Approve a manually-confirmed task
POST   /api/ext/comments/{id}/dispute   Dispute a manually-confirmed task
GET    /api/ext/comments/{id}/verifications  Verbose verifier timeline

Pricing

1 credit per new comment task. In a batch, TokPortal validates every row first. The debit for accepted rows and all accepted task inserts then commit in one database transaction. Rejected rows are never charged. This prevents a task from existing without its matching debit, or a debit from existing without its matching task.

The task's exact stored cost is refunded atomically if:

  • you cancel a pending task via DELETE /api/ext/comments/{id}
  • the 72-hour hard deadline expires before the manager posts (auto-cancellation)

Current tasks refund 1 credit. Historical tasks can have a different stored cost, so always read credits_refunded from the response instead of assuming an amount.

The CM payout is paid out of TokPortal funds — it does not affect your credit balance.

TokPortal Coverage requirement

The saved account must either have active TokPortal Coverage or be permanently grandfathered. It must also belong to the caller and have an assigned account manager. A single-task request that cannot execute returns MANAGED_ACCOUNT_TASK_BLOCKED (409). A batch keeps partial-success semantics and places the stable account or Coverage reason in rejected[*].reason.

If Coverage later pauses or lapses, the task remains visible to the client but is removed from the manager's executable queue. Its durable workflow status is preserved. Read execution_blocked, execution_blocked_at, and execution_block_reason, then fetch GET /api/ext/accounts/{saved_account_id}/managed-subscription for the authoritative state and reactivation quote. Cancellation of a still-pending task remains available while Coverage is paused.

Supported platforms

PlatformComment postingReply-to-comment targetAuto-verificationComment max length
TikTok150 chars
Instagram2,200 chars
YouTube❌ (coming)

Auto-verification scrapes up to 100 of the target video's most recent comments and matches them by author handle + text similarity (Sørensen-Dice ≥ 0.95). For a comment target, the verifier additionally pulls replies and matches the manager's reply the same way (by handle + text) — it does not require the reply to sit under a specific parent comment.

Lifecycle

A task moves through these states. Statuses surface verbatim in GET /api/ext/comments/{id} so your code can branch on them.

StatusMeaningVisible in API
pendingAwaiting the account manager to post the comment. Hard deadline: 72h.
submittedManager declared they posted. Auto-verifier ran with a 30s grace window — still not matched. The CM should either retry (if a propagation lag) or manual-confirm.
verified_autoAuto-verifier matched the comment on the target video. Payout locked in 24h (auto-finalize).
manually_confirmedAuto-verification couldn't find the comment; manager swore they posted. You have 72 hours to approve or dispute. After that, payout auto-locks.
pending_correctionsThe manager is fixing something you disputed. Hidden if it was an auto-detected issue (the manager is fixing it before you ever see it).✅ (only client-disputed)
finalizedPayout was locked, manager wallet credited. Terminal state.
cancelledCancelled by you (DELETE) or by the 72h expiry sweep. Credit refunded.
rejected / needs_reviewInternal — should never appear via the API.hidden

Lifecycle diagram (happy path)

   create
     │
     ▼
  pending  ─── manager posts ───► submitted
                                     │
                ┌─── verifier matches ▼ ────┐
                │                            │
                ▼                            ▼
          verified_auto                manually_confirmed
                │                            │
                │ (24h auto-finalize)        │ you approve  ───► finalized
                ▼                            │ you dispute  ───► pending_corrections
            finalized                        │ 72h pass     ───► finalized (auto)
                                             ▼
                                       ─ pending_corrections
                                       │ manager fixes + retries verify
                                       ▼
                                   verified_auto / manually_confirmed

Error handling

All endpoints return a uniform error envelope:

{
  "error": {
    "code": "COMMENT_PLATFORM_MISMATCH",
    "message": "The video URL's platform does not match the account's platform...",
    "details": { "account_platform": "tiktok", "url_platform": "instagram" }
  }
}

Comment-specific error codes

CodeHTTPTrigger
COMMENT_TASK_NOT_FOUND404Task ID doesn't exist or doesn't belong to your account.
COMMENT_TASK_NOT_OWNED403Task exists but belongs to another user.
COMMENT_INVALID_STATUS409Action not allowed in current status (e.g. cancel a finalized task).
COMMENT_ACCOUNT_NOT_MANAGED409The target account has no current_cm_id. Wait for an order to be in progress.
COMMENT_PLATFORM_MISMATCH400Target platform ≠ account platform.
COMMENT_INVALID_VIDEO_URL400Could not parse the video URL.
COMMENT_INVALID_COMMENT_URL400target_comment_url is not a recognizable TikTok comment link.
COMMENT_NOT_A_COMMENT_URL400The link resolved to a video, not a specific comment.
COMMENT_TARGET_PLATFORM_UNSUPPORTED400Comment targets (replies) are TikTok-only.
COMMENT_TEXT_TOO_LONG400comment_text exceeds the platform's character limit.
COMMENT_TEXT_EMPTY400comment_text is blank.
COMMENT_DISPUTE_REASON_REQUIRED400Dispute call missing or short reason field.
INSUFFICIENT_CREDITS402Not enough credits for the requested batch.
MANAGED_ACCOUNT_TASK_BLOCKED409Coverage is inactive or the account is detached, banned, missing Coverage, or otherwise unavailable. Read details.reason, then fetch the account Coverage endpoint.
SAVED_ACCOUNT_NOT_FOUND404saved_account_id doesn't match any of your accounts.
SAVED_ACCOUNT_NOT_OWNED403Account belongs to someone else.

When creating a batch, the response always succeeds at HTTP-201 even if individual rows are rejected. Inspect created / rejected to surface per-row results.

Batch behaviour vs single-shot

The POST /api/ext/comments body accepts either a single object or { "tasks": [...] }. The two paths differ in error semantics:

  • Single object → if the row is rejected at validation, the endpoint returns the matching 400/409/404 error code. Easier to detect failure.
  • Batch (tasks: [...]) → always returns 201 with a rejected array even if every row fails. The batch is partial-success — the rows that pass are still created.

What auto-verification actually checks

The verifier runs once, 30 seconds after the manager clicks "I posted it" (so the platform has time to index the new comment). It then:

  1. Scrapes the target video's last ~100 comments via Apify (plus replies, for comment targets).
  2. Filters to comments whose author handle matches the saved account. For a comment target, replies are scraped too and matched the same way (handle + text) — the reply doesn't have to sit under a specific parent comment.
  3. Computes Sørensen-Dice text similarity vs your comment_text.
  4. Decides:
    • ≥ 0.95 + same handleverified_auto
    • < 0.95 + same handle (text drifted)pending_corrections, manager is asked to edit/repost
    • ≥ 0.92 + different handle (text matches but wrong account) → pending_corrections, manager asked to delete + repost from the right account
    • nothing matches → manager is offered the manual confirmation modal, which moves the task into submitted (still in flight) or manually_confirmed (your turn)

You can fetch the full verifier timeline via GET /api/ext/comments/{id}/verifications.

Rate limits & quotas

  • API rate limit: 120 req/min per key (shared with the rest of the TokPortal API).
  • Batch size cap: 200 tasks per POST body.
  • Hard deadline per task: 72 hours between creation and submitted. Tasks that expire are auto-cancelled and credits refunded.
  • While TokPortal Coverage blocks execution, withheld tasks do not consume the manager's queue or expire as late work.