Skip to main content

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: tok_live_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: tok_live_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

import requests, time

KEY = "tok_live_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()