Review status of every TikTok Smart+ ad of an advertiser
Changed onReturns the review verdict of every Upgraded Smart+ ad of one TikTok advertiser, with each creative's verdict, in one paginated read. Use it to refresh reviews periodically: one call (plus its pages) per advertiser per refresh, instead of GET /v1/ads/{adId}/tiktok-smart-plus-review per ad.
Zernio lists the advertiser's Smart+ ads with /smart_plus/ad/get/ (deleted ones only with includeDeleted=true) and reads /smart_plus/ad/review_info/ for Smart+ ads holding up to 50 creatives in total per call (TikTok refuses more; a Smart+ ad with more than 50 creatives is read alone), across ad groups, one call after another. A full refresh of N Smart+ ads with C creatives in total costs about ceil(N / 100) listing calls and ceil(C / 50) review calls on TikTok. When TikTok still refuses a call for its creative count, Zernio lowers the creative cap for that advertiser and reads the same ads again in smaller calls, never resending the refused size.
Stale while refreshing: every review is stored for 24 hours per connection, advertiser and Smart+ ad (shared with the single-ad read), and readAt is always the time TikTok answered, never rewritten when served from the store. maxAgeSeconds (default 3600) is the freshness window: a review read within it is fresh and costs no TikTok call; an older one is still returned in items but is read again, and so is a Smart+ ad never read. Each request first reads every Smart+ ad of the page never read (live, then deleted with includeDeleted=true) and only then refreshes stale ones, oldest readAt first, so a quota pause cannot leave never-read ads behind stale ones, progress carries over between requests and an ad already read never goes back to pending. A stored review is replaced only by a successful read. counts splits the Smart+ ads on this page into fresh, stale, pending and failed, and oldestReadAt is the oldest readAt of items. incomplete is true only while some Smart+ ad of the page has never been read (pending > 0). Staleness is reported apart: allFresh is true when every item and refusal of the page is within maxAgeSeconds and nothing is pending. A page with stale items and nothing pending is complete (incomplete: false, no Retry-After): move on, and a later read refreshes it oldest first. On 2026-10-25 TikTok's quota allowed about 130 to 230 Smart+ ads per advertiser per hour (about 11.5 ads and 4 creatives per successful call), so a larger advertiser cannot be fully refreshed within one hour and its pages stay complete but not allFresh.
The listing is stored with the time it was read (listing.readAt) and listed again when it is older than maxAgeSeconds, so it can be up to maxAgeSeconds old: a Smart+ ad created on TikTok appears after at most that long (one hour by default). If that relisting fails, Zernio serves the stored listing with listing.source: fallback and the relist error in listing.error, instead of failing the request; listing.source: fresh means the listing was read within maxAgeSeconds. Only when no listing was ever stored does the listing error fail the request.
TikTok's review endpoint has a strict quota of its own (TikTok documents neither the quota nor its scope). When it is over quota (or Zernio is holding review reads for this advertiser and connection after an overage: about 60 seconds, then 120, 240, 480 and up to 960 while TikTok keeps refusing, and after each successful call one step less, 480 down to 60 seconds, until a success at 60 seconds ends it, each with up to 10% of random jitter), Zernio stops calling TikTok and answers 200 with the reviews it has: stale reviews in items, the Smart+ ads never read in pendingSmartPlusAdIds and, when any are pending, incomplete: true with retryAfterSeconds (also in the Retry-After header). Every Smart+ ad of the page is in items, failedSmartPlusAds or pendingSmartPlusAdIds. Wait retryAfterSeconds and read the same page again: only the stale and pending ads reach TikTok.
A Smart+ ad whose review TikTok refuses on its own (for example one deleted on TikTok since the listing was read) is returned in failedSmartPlusAds with TikTok's error and refusedAt, and the rest of the page is still read. Zernio finds it by splitting the refused batch in halves, at most 16 extra TikTok calls per page; ads still unresolved after that keep their stored review, or stay in pendingSmartPlusAdIds when they have none, and are read first by the next request. A refusal of a single ad is stored for 24 hours and read again once it is older than maxAgeSeconds; when an ad has both a stored review and a stored refusal, the more recent one is returned. When both halves of a refused batch are refused with the same TikTok error (for example a permission error), Zernio stops calling TikTok for that page: when every Smart+ ad of the page has a stored review or refusal, it serves them and returns the refusal in reviewError; when some ad was never read, the whole request fails with that error.
Items are sorted by adGroupId, then smartPlusAdId, so pages are stable. Keep one page in flight per advertiser and read its pages one after another: parallel pages of one advertiser spend its review quota at the same time and come back incomplete. Production logs suggest the quota is counted per advertiser (not confirmed by TikTok), so different advertisers have been read in parallel without throttling each other.
Request
- Base URL: https://zernio.com/api
- URL: https://zernio.com/api/v1/ads/tiktok-smart-plus-reviews
- Auth: HTTP bearer
Query parameters
A tiktok or tiktokads account ID
TikTok advertiser ID
Also return Smart+ ads deleted on TikTok (listed with primary_status: STATUS_ALL).
Freshness window in seconds. Reviews, refusals and the listing read within it are served without calling TikTok; older ones are still returned but read again, oldest first.
Response
The reviews of one page of the advertiser's Smart+ ads. Check incomplete: when true, some Smart+ ads of the page were never read. allFresh says whether every review is within maxAgeSeconds.
Changes
- info
added the new optional
queryrequest parametermaxAgeSeconds - info
added the optional property
to the response with the status - info
added the optional property
to the response with the status - info
added the optional property
//to the response with the status - info
added the optional property
to the response with the status - info
added the optional property
to the response with the status - info
added the optional property
to the response with the status - info
added the optional property
to the response with the status
- info
- info
endpoint added
- info