Comments

Approve & Dispute – Review Flow

Approve or dispute a manually-confirmed comment task. The manager has 72 hours to wait for your decision before payout auto-locks.

Approve & Dispute

When the auto-verifier can't find a comment but the manager swears they posted it, the task moves to manually_confirmed and you get a 72h window to:

  • Approve — pay the manager immediately, skip the wait.
  • Dispute — send a reason back to the manager so they fix it. The task flips to pending_corrections; once they re-verify, it moves on.

If you do nothing for 72 hours, the task auto-finalizes (the manager is paid).

Approve

POST /api/ext/comments/{id}/approve
curl -X POST https://app.tokportal.com/api/ext/comments/0d8b5a3e-92c4-4111-9a7d-3e2f1a2b3c4d/approve \
  -H "X-API-Key: sk_xxx"

Response (200):

{
  "data": {
    "id": "0d8b5a3e-92c4-4111-9a7d-3e2f1a2b3c4d",
    "status": "finalized",
    "platform": "tiktok",
    "cm_payout_amount": 0.24,
    "submitted_at": "2026-04-27T17:21:34Z",
    "manually_confirmed_at": "2026-04-28T13:56:11Z",
    "finalized_at": "2026-04-28T13:56:17Z",
    "...": "..."
  }
}

The payout is computed from submitted_at → manually_confirmed_at (the same speed-tier table as auto-verified tasks).

Errors

  • 404 COMMENT_TASK_NOT_FOUND — bad ID.
  • 403 COMMENT_TASK_NOT_OWNED — belongs to another user.
  • 409 COMMENT_INVALID_STATUS — task isn't in manually_confirmed. details.current_status tells you where it actually is.

Dispute

POST /api/ext/comments/{id}/dispute

Body:

FieldTypeRequiredDescription
reasonstringyes3–500 characters. The manager will see this verbatim and use it to fix the comment.
curl -X POST https://app.tokportal.com/api/ext/comments/0d8b5a3e-92c4-4111-9a7d-3e2f1a2b3c4d/dispute \
  -H "X-API-Key: sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Cannot find the comment under the video, please re-post."
  }'

Response (200):

{
  "data": {
    "id": "0d8b5a3e-92c4-4111-9a7d-3e2f1a2b3c4d",
    "status": "pending_corrections",
    "correction_required": "The client reviewed your comment and reported a problem:\n\n\"Cannot find the comment under the video, please re-post.\"\n\nPlease fix the issue and click \"I fixed it — re-check\" once done.",
    "manually_confirmed_at": null,
    "client_dispute_deadline_at": null,
    "...": "..."
  }
}

The task is now in pending_corrections. The manager fixes it and re-runs the auto-verifier — on success the task lands in verified_auto (or manually_confirmed again, if the verifier still can't see it). You can keep iterating: dispute again, approve, or just wait.

Errors

  • 400 COMMENT_DISPUTE_REASON_REQUIREDreason missing or too short.
  • 409 COMMENT_INVALID_STATUS — task isn't in manually_confirmed.
  • All the standard 401/403/404s.

A complete review loop in pseudo-code



KEY = "sk_xxx"
BASE = "https://app.tokportal.com/api/ext"

def review_pending():
    r = requests.get(f"{BASE}/comments?status=manually_confirmed",
                     headers={"X-API-Key": KEY}).json()
    for task in r["data"]:
        timeline = requests.get(
            f"{BASE}/comments/{task['id']}/verifications",
            headers={"X-API-Key": KEY}).json()["data"]

        # Custom logic — e.g. auto-approve if last attempt's
        # comments_scraped is 0 (likely an Apify miss, not a real no-show).
        last = timeline["attempts"][-1] if timeline["attempts"] else None
        if last and last["comments_scraped"] == 0:
            requests.post(f"{BASE}/comments/{task['id']}/approve",
                          headers={"X-API-Key": KEY})
        else:
            requests.post(f"{BASE}/comments/{task['id']}/dispute",
                          headers={"X-API-Key": KEY,
                                   "Content-Type": "application/json"},
                          json={"reason": "Cannot locate the comment under the video."})

review_pending()