---
title: "Review status of each creative in a TikTok Smart+ ad"
method: GET
path: "/v1/ads/{adId}/tiktok-smart-plus-review"
tags: ["Ad Campaigns"]
---

# Review status of each creative in a TikTok Smart+ ad

`GET /v1/ads/{adId}/tiktok-smart-plus-review`

## Request

- Base URL: `https://zernio.com/api`
- URL: `https://zernio.com/api/v1/ads/{adId}/tiktok-smart-plus-review`
- Auth: HTTP bearer

Shows which Spark post, video or carousel of an Upgraded Smart+ ad TikTok approved or rejected, with every rejection reason, keyed by the TikTok post id for a Spark post.

Reads TikTok's `/smart_plus/ad/review_info/` live (read-only, works on a paused ad) for the
Smart+ ad that holds `adId`, and returns the ad-level verdict plus one entry per creative.
`adId` may be the Smart+ ad itself or any creative of it synced as its own ad: Zernio finds
the Smart+ ad in the ad's ad group through `/smart_plus/ad/get/`, and uses the ad group's only
Smart+ ad when no creative list names the ad.

`materialType`, `tiktokItemId`, `videoId`, `name` and `operationStatus` come from the Smart+
ad's `creative_list`. TikTok leaves out of that list the creatives it added on its own
(creator content, authorized TikTok posts, Creative Library content) and lists each image of a
carousel under its own material id, so those entries come back with the review verdict and
null descriptive fields. TikTok returns no review timestamp; `readAt` is when Zernio read it.

## Path parameters

- `adId` string, required

## Response `200`

The Smart+ ad's review verdict per creative

- object
  - `adId` string
  - `platform` 'tiktok'
  - `platformAdId` string
  - `smartPlusAdId` string: The TikTok Smart+ ad whose review this is.
  - `review` object, nullable: The ad-level verdict (`smart_plus_ad_review_infos`). Null when TikTok returned none.
    - `reviewStatus` 'approved' | 'partially_approved' | 'rejected' | 'unknown': TikTok `review_status` normalized: ALL_AVAILABLE -> approved, PART_AVAILABLE -> partially_approved (delivers in part of the targeted locations), UNAVAILABLE -> rejected, anything else or missing -> unknown (see `rawReviewStatus`).
    - `rawReviewStatus` string, nullable: TikTok `review_status`, verbatim.
    - `rejectReasons` string[]: Every distinct reason across `rejections`.
    - `passedLocations` string[]: Location codes that passed the review.
    - `appealStatus` string, nullable: TikTok `appeal_status`, verbatim: NOT_APPEALED, APPEALING, APPEAL_SUCCESSFUL, APPEAL_FAILED, APPEAL_DONE.
    - `appealRejectReasons` string[]
    - `rejections` TikTokReviewRejection[]
      - `reasons` string[]
      - `suggestion` string, nullable: TikTok's advice for fixing the rejection.
      - `forbiddenPlacements` string[]
      - `forbiddenAges` string[]
      - `forbiddenLocations` string[]
      - `content` object, nullable: The content TikTok rejected.
        - `type` string, nullable: TikTok `content_type`, verbatim (ModeString, ModeImage, ModeVideo, ModeMusic, LandingPage, ...).
        - `text` string, nullable
        - `imageId` string, nullable
        - `videoId` string, nullable
        - `musicId` string, nullable
  - `materials` object[]: One entry per creative TikTok reviewed (`material_review_infos`).
    - `adMaterialId` string: TikTok `ad_material_id` of the creative inside this ad.
    - `materialType` 'spark_post' | 'video' | 'carousel' | 'catalog_carousel' | 'null', nullable: Null for a creative TikTok added on its own or a carousel image.
    - `tiktokItemId` string, nullable: The TikTok post id when the creative is a Spark post.
    - `videoId` string, nullable
    - `name` string, nullable
    - `operationStatus` string, nullable: TikTok `material_operation_status`: ENABLE or DISABLE.
    - `reviewStatus` 'approved' | 'partially_approved' | 'rejected' | 'unknown': TikTok `review_status` normalized: ALL_AVAILABLE -> approved, PART_AVAILABLE -> partially_approved (delivers in part of the targeted locations), UNAVAILABLE -> rejected, anything else or missing -> unknown (see `rawReviewStatus`).
    - `rawReviewStatus` string, nullable: TikTok `review_status`, verbatim.
    - `rejectReasons` string[]: Every distinct reason across `rejections`. Empty when approved.
    - `passedLocations` string[]
    - `rejections` TikTokReviewRejection[]
      - `reasons` string[]
      - `suggestion` string, nullable: TikTok's advice for fixing the rejection.
      - `forbiddenPlacements` string[]
      - `forbiddenAges` string[]
      - `forbiddenLocations` string[]
      - `content` object, nullable: The content TikTok rejected.
        - `type` string, nullable: TikTok `content_type`, verbatim (ModeString, ModeImage, ModeVideo, ModeMusic, LandingPage, ...).
        - `text` string, nullable
        - `imageId` string, nullable
        - `videoId` string, nullable
        - `musicId` string, nullable
  - `readAt` string, date-time: When the verdict was read from TikTok.

## Other responses

- `400`: Invalid request
- `401`: Missing or invalid API key. `code` is `missing_credentials` when no Authorization header was sent and `invalid_credentials` when the key is unknown, revoked or expired.
- `404`: Ad not found, it has no TikTok ad or ad group id yet, or no Smart+ ad of its ad group holds it
- `422`: The TikTok ad is not an Upgraded Smart+ ad (read it with GET /v1/ads/{adId}/review)
- `429`: The connected account's upstream platform quota is exhausted. Reddit rate-limits per connected Reddit user (1000 requests per 10-minute window), and that budget is shared by every operation using that account. Retry after the window resets rather than retrying immediately; repeated calls while exhausted do not succeed and keep the budget spent. Google Ads: writes and reports run on one developer token shared by every Google Ads account on Zernio. The token holds Standard access (no daily operations cap), so this only happens when Google throttles the token or your ad account. The envelope has `code: rate_limited`, `platform: google`, `details.quotaScope: DEVELOPER` (`ACCOUNT` when it is your own ad account's quota), `details.resetsAt` (ISO instant when Google accepts requests again) and `Retry-After` counting down to it. Retrying earlier cannot succeed. Meta ads: every Meta throttle (codes 4, 17, 32, 613 and the business-use-case codes 80000-80014) returns 429 `rate_limited`, even when Meta itself answers HTTP 400. `Retry-After` comes from Meta's `x-business-use-case-usage` estimate when Meta sends one, otherwise it is Meta's documented 60-second minimum (30 seconds for the one-write-per-30-seconds limit on a single object). Pinterest ads: Pinterest rate-limits per user and app, per category (ads_read, ads_write, ads_analytics). `Retry-After` comes from Pinterest's `x-ratelimit-reset` when it sends one, otherwise 60 seconds.
- `501`: Only supported on TikTok

## Changes

- **2026-10-21** `a0835f2c551a`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/zernio/apis/zernio-api/changes/v1/ads/:adId/tiktok-smart-plus-review/get.md)

---

[API](https://skmtc.dev/zernio/apis/zernio-api.md) · [All operations](https://skmtc.dev/zernio/apis/zernio-api/llms.txt) · [OpenAPI document](https://skmtc.dev/zernio/apis/zernio-api/revisions/4e74db179e73?raw)
