Replying to a TikTok comment through an API looks like a simple write operation:
post_id + comment_id + text → reply
In production, however, the difficult part is not sending the request. It is proving that the selected post and comment are valid targets—and handling cases where the reply outcome is uncertain.
A safe workflow should:
- Select a post owned by the connected TikTok account.
- Retrieve its top-level comments.
- Preserve every provider ID as a string.
- Let the operator review the exact target and reply.
- Submit the reply once.
- Avoid automatically retrying an uncertain write.
This article demonstrates that workflow using the UnifyPort API.
Understand the operation boundary
A public TikTok comment is not a private conversation. You should not send comment replies through a generic messaging or DM endpoint.
The relevant operations are:
| Task | Method and endpoint |
|---|---|
| List posts owned by an account | GET /v1/accounts/{account_id}/posts |
| Inspect a selected post | POST /v1/accounts/{account_id}/posts/info |
| List top-level comments | POST /v1/accounts/{account_id}/posts/comments/list |
| Reply to a top-level comment | POST /v1/accounts/{account_id}/posts/comments/reply |
This workflow applies to posts owned by the connected TikTok account. It is not an arbitrary-video commenting interface.
The connected account should also be authorized and running before these operations are enabled.
Step 1: Verify the post
Start by listing the posts belonging to the selected account. When the user chooses one, inspect it again before enabling comment actions.
Do not treat a pasted TikTok URL as proof that the account owns the post.
Keep these values associated with one another:
const selection = {
accountId: "connected-account-id",
postId: "7481234567890123456"
};
TikTok identifiers can exceed JavaScript's safe integer range. Preserve them as strings throughout storage, API requests, UI state, and logs.
Avoid this:
const postId = Number(apiResult.post_id);
Use this instead:
const postId = apiResult.post_id;
A useful validation rule for a returned post ID is:
function isValidPostId(value) {
return typeof value === "string" && /^[1-9][0-9]*$/.test(value);
}
Step 2: List top-level comments safely
Send the verified post_id to the comment-list endpoint:
async function listTikTokComments({
apiKey,
accountId,
postId,
cursor
}) {
const body = {
post_id: postId,
limit: 20
};
if (cursor) {
body.cursor = cursor;
}
const response = await fetch(
`https://api.unifyport.ai/v1/accounts/${encodeURIComponent(accountId)}/posts/comments/list`,
{
method: "POST",
headers: {
"X-Api-Key": apiKey,
"Content-Type": "application/json"
},
body: JSON.stringify(body)
}
);
return response.json();
}
Omit cursor from the first request. If the response reports has_more: true, pass next_cursor back unchanged.
Do not assume that receiving fewer than 20 comments means pagination is complete. Follow has_more.
Each pagination chain should remain attached to its original account and post:
const paginationState = {
accountId,
postId,
nextCursor,
hasMore
};
This prevents a cursor obtained for one post from being reused after the operator switches to another post.
The comment-list operation covers top-level comments. It should not be treated as a complete history of every nested reply.
Step 3: Bind the approved reply to its target
Before dispatch, show the operator:
- The connected account
- The selected post
- The selected comment
- The reply text
Store the reviewed values together:
const approvedReply = {
accountId,
postId,
commentId,
text,
approvedAt: new Date().toISOString()
};
This matters because refreshing the comment list could otherwise change the current selection while leaving the draft text intact.
The write should always use the reviewed record—not whatever comment happens to be selected in the UI at dispatch time.
Step 4: Submit the reply once
Here is a minimal helper for submitting the reviewed reply:
async function replyToTikTokComment({
apiKey,
accountId,
postId,
commentId,
text
}) {
if (
typeof postId !== "string" ||
!/^[1-9][0-9]*$/.test(postId)
) {
throw new Error("Use the returned post ID string");
}
if (
typeof commentId !== "string" ||
!commentId.trim()
) {
throw new Error("Select a valid comment");
}
if (
typeof text !== "string" ||
!text.trim()
) {
throw new Error("Reply text cannot be blank");
}
const response = await fetch(
`https://api.unifyport.ai/v1/accounts/${encodeURIComponent(accountId)}/posts/comments/reply`,
{
method: "POST",
headers: {
"X-Api-Key": apiKey,
"Content-Type": "application/json"
},
body: JSON.stringify({
post_id: postId,
comment_id: commentId,
text
})
}
);
const result = await response.json();
return {
httpStatus: response.status,
result
};
}
Keep the API key on your backend. It should never be embedded in browser code or exposed to end users.
Also suppress repeated clicks and serialize writes targeting the same comment. These are useful application safeguards, but they are not substitutes for API-level idempotency.
Interpret accepted carefully
A successful response may contain:
{
"data": {
"status": "accepted"
}
}
accepted means the request was accepted. It does not prove that the reply is already publicly visible.
If a reliable created-comment receipt is included, preserve it. Do not require that optional receipt before recognizing acceptance.
Your application state could distinguish:
const replyStatus = {
state: "accepted",
publiclyVisible: "unknown"
};
That is more accurate than immediately displaying “Reply published.”
Never blindly retry an uncertain reply
Read operations and write operations need different retry policies.
If listing comments fails before returning data, retrying the read is usually reasonable.
A reply request is different. The provider may have created the reply even when your application did not receive a complete response.
For example:
- Your application sends the reply.
- The provider accepts it.
- The connection times out before the response reaches your application.
- A generic retry creates a duplicate reply.
For a timeout, connection interruption, or unconfirmed write receipt, store an unknown outcome:
const replyAttempt = {
state: "unknown",
accountId,
postId,
commentId,
text,
requestId,
automaticRetryAllowed: false
};
Send this attempt to manual review instead of automatically repeating it.
A later top-level comment read that does not show the reply is not definitive proof that the first write failed.
Handle errors by meaning
Different results require different recovery actions:
| Result | Recommended action |
|---|---|
200 with status: accepted
|
Save acceptance without claiming public visibility |
403 post_inaccessible |
Stop and investigate account access |
404 post_not_found |
Refresh the post selection |
404 comment_not_found |
Refresh and reselect the comment |
501 unsupported_by_provider |
Stop; do not silently switch to a DM |
502 reply_post_comment_failed with an unconfirmed outcome |
Mark for review and do not automatically resend |
Do not translate post_inaccessible into “the post was deleted” unless you have separate evidence confirming deletion.
Similarly, comment_not_found does not prove that every nested reply was searched. It only tells you that the requested target could not be verified through this operation.
Treat webhook events as notifications, not complete history
A comment-created webhook can help your application notice new activity, but it should remain a separate intake layer.
Webhook events may be:
- Delayed
- Duplicated
- Reordered
- Missing
Verify webhook signatures and deduplicate events by their event IDs.
Do not treat webhook delivery as proof that your reply was displayed, and do not assume a missing webhook means the reply failed.
If comment polling requires an account setting such as provider_data.enable_comment: true, confirm the environment behavior and reconnect requirements before relying on it.
Production checklist
Before enabling TikTok comment replies, verify that your application:
- Confirms the connected account is authorized and running.
- Allows selection only from posts owned by that account.
- Preserves post and comment IDs as strings.
- Follows
has_moreandnext_cursorfor pagination. - Restricts this workflow to verified top-level comments.
- Shows the final account, post, comment, and text before dispatch.
- Prevents double-click submissions.
- Records the request ID and HTTP result.
- Does not automatically retry uncertain writes.
- Does not log API keys or unnecessary customer comment text.
- Does not interpret
acceptedas guaranteed public visibility.
The most important design principle is simple:
Reads can often be retried. An uncertain public write should be reviewed before it is repeated.
That distinction prevents a temporary network problem from becoming a visible duplicate reply.
This article was adapted from an original UnifyPort technical guide with AI-assisted editing.
Top comments (0)