← back to Marketing Command Center

docs/submissions/tiktok-app-review.md

214 lines

# TikTok App Review — Submission Package

**App:** DW Marketing · **app_id** `7662772350357866516` · developers.tiktok.com
**Owner:** @designerwallcoverings (Individual)
**Goal:** get the **PRODUCTION** app approved for `video.publish` (Direct Post) + `video.upload`
so `@designerwallcoverings` can post **PUBLICLY** from the Marketing Command Center.
Today the app is unaudited → sandbox-only, private (`SELF_ONLY`) posts only.

**Status going in (all verified this session):**
- Domain `designerwallcoverings.com` **verified** in the portal (apex TXT).
- Sandbox fully configured; a real end-to-end **SELF_ONLY post was published** to
  `@designerwallcoverings` (publish_id `v_pub_file~v2-1.766506…`) — proves the Content Posting API works.
- Both policy URLs return **HTTP 200** (verified `curl` this session).
- App icon present at `~/Desktop/Images/DW-TikTok-icon.png` (1024×1024 PNG).
- The MCC is the integration surface; OAuth + `postTikTok()` are live in `modules/channels/index.js`.

---

## 1. Production-app field values (paste-ready)

TikTok dev portal → **Manage apps → DW Marketing → Production** tab → App details.
Copy each cell verbatim.

| Field | Value to paste |
|---|---|
| **App icon** | Upload `~/Desktop/Images/DW-TikTok-icon.png` (1024×1024 PNG) |
| **App name** | `DW Marketing` |
| **Category** | `Shopping` |
| **Description** (≤120 chars) | `Designer Wallcoverings posts its own product and room videos to its official TikTok via the Content Posting API.` |
| **Terms of Service URL** | `https://designerwallcoverings.com/policies/terms-of-service` |
| **Privacy Policy URL** | `https://designerwallcoverings.com/policies/privacy-policy` |
| **Platform** | `Web` |
| **Web/Desktop URL** | `https://marketing.designerwallcoverings.com` |
| **Products** | `Login Kit` + `Content Posting API` |
| **Scopes** | `user.info.basic`, `video.publish`, `video.upload` |
| **Redirect URI** | `https://marketing.designerwallcoverings.com/api/channels/oauth/tiktok/callback` |

Description character count = **111** (≤120 ✓).

**Hard rules the reviewer enforces — do not trip these:**
- The **Web/Desktop URL domain MUST match** the domain shown on screen in the demo video →
  both are `marketing.designerwallcoverings.com`. ✓
- **No `localhost`** anywhere (redirect URI or web URL) — TikTok auto-rejects it.
- The live MCC's `OAUTH_REDIRECT_BASE` is already `https://marketing.designerwallcoverings.com`,
  so the redirect URI above is the exact one the callback code uses.
- ToS + Privacy URLs must resolve (verified 200 this session).

---

## 2. "Explain how each product and scope works" — reviewer free-text

Paste this verbatim into the App Review "describe how your app uses each scope/product" field.
It is written so a reviewer can approve without follow-up: it establishes that this is a
**single-brand, own-account** integration with no third-party or user-generated content.

> Designer Wallcoverings (designerwallcoverings.com) runs a private Marketing Command Center at
> marketing.designerwallcoverings.com that manages our OWN brand's social channels. The TikTok
> integration lets our marketing team authenticate our OWN official account
> (@designerwallcoverings) and publish our OWN product and room-setting videos to it. There is no
> third-party content, no user-generated content, and no multi-account behavior — every action is
> our brand posting to our brand's single account.
>
> **Login Kit — `user.info.basic`:** When our admin clicks "Connect TikTok" on the Command
> Center's Channels page, we run the Login Kit OAuth flow to authenticate our own TikTok account.
> We read `open_id`, `avatar_url`, and `display_name` only, and only to confirm and display in the
> dashboard which account is connected. No other user's data is ever accessed.
>
> **Content Posting API — `video.publish` (Direct Post):** From the Command Center, our team
> selects a wallcovering product or room-setting video we produced and publishes it directly to our
> own @designerwallcoverings profile via the Content Posting API (Direct Post). The video source is
> fetched via PULL_FROM_URL from our verified domain designerwallcoverings.com, or uploaded as
> bytes via FILE_UPLOAD. This is how we announce new collections and room visualizations on TikTok.
>
> **Content Posting API — `video.upload` (draft fallback):** As a fallback, we upload a video as a
> draft to our own account's TikTok inbox so a team member can finalize the caption and timing and
> post it manually from the TikTok app.
>
> All posting is to our own single brand account. The domain designerwallcoverings.com is verified
> in the developer portal and is the source for PULL_FROM_URL video content.

---

## 3. The required demo video — shot list / script

TikTok App Review **mandates** a screen-recording that shows the complete end-to-end integration
flow and **demonstrates every requested scope**. This is the part that decides the review.

### Recording constraints (from the portal)
- Format **mp4 or mov**, **≤50 MB per file**, up to 5 files.
- **Must use the SANDBOX** app (client key `sbaw22ejwjsfwqetsy`) — production isn't approved yet,
  so record the flow against sandbox, where posts land private (`SELF_ONLY`).
- The **on-screen domain must match** the Web/Desktop URL → keep
  `https://marketing.designerwallcoverings.com` visible in the address bar.
- **All three scopes must be visibly demonstrated:** `user.info.basic` (connected account shows
  avatar + name), `video.publish` (Direct Post → publish_id → video on account),
  `video.upload` (draft lands in inbox).
- Target length **~2–3 min**, narrated. Keep the mouse movements slow and deliberate.

### This flow is already filmable
A real `SELF_ONLY` post has already been fired end-to-end to @designerwallcoverings
(publish_id `v_pub_file~v2-1.766506…`), so nothing about Scenes 3–4 is theoretical — the exact
button-press sequence works and can be filmed live.

> **One constraint to handle while filming (unaudited-app rule):**
> `unaudited_client_can_only_post_to_private_accounts`. Before recording the post scenes, toggle
> **@designerwallcoverings → Private ON**, record the post, then toggle **Private OFF** after.
> A `SELF_ONLY` privacy level on the post alone is NOT enough for the unaudited sandbox — the
> ACCOUNT itself must be Private during the post. This is a recording-time step only; production
> approval removes it.

### Scene-by-scene

**Scene 1 — Context (0:00–0:15)**
- On screen: Chrome with the address bar clearly reading `https://marketing.designerwallcoverings.com`.
- Show the Command Center dashboard, then navigate to the **Channels** page with the TikTok card
  in its disconnected state.
- Narration: *"This is the Designer Wallcoverings Marketing Command Center at
  marketing.designerwallcoverings.com. We use it to post our own brand videos to our own TikTok
  account. Here's the Channels page."*

**Scene 2 — Login Kit + `user.info.basic` (0:15–0:50)**
- Click **Connect TikTok** on the TikTok card.
- The TikTok OAuth consent screen appears — pause on it so the reviewer sees the app name
  "DW Marketing" and the requested scopes (`user.info.basic`, `video.publish`, `video.upload`).
- Click **Authorize / Continue** → redirected back to the Channels page, now showing TikTok
  **Connected** with the account **avatar + display name** rendered.
- Narration: *"We connect our own TikTok account through Login Kit. It asks consent for the three
  scopes. After authorizing, the dashboard shows our connected account — that's user.info.basic,
  which we use only to confirm which account is linked."*

**Scene 3 — `video.publish` Direct Post (0:50–1:50)**
- Select one of our product/room videos in the Command Center.
- Choose **Post to TikTok → Direct Post** → confirm.
- Show the success state with the returned **`publish_id`** clearly on screen.
- Cut to the TikTok app / profile showing the newly posted video (sandbox = private/SELF_ONLY).
- Narration: *"We select one of our own product videos and publish it directly to our account via
  the Content Posting API. The API returns a publish_id, and the video appears on our
  @designerwallcoverings profile. That's video.publish."*

**Scene 4 — `video.upload` draft (1:50–2:20)**
- Repeat with the **Upload as draft** option.
- Show the video landing in the TikTok **inbox as an editable draft**.
- Narration: *"As a fallback we can upload a video as a draft to our own inbox to finish the
  caption and post manually. That's video.upload."*

**Scene 5 — Close (2:20–2:30)**
- Return to the Channels page showing **connected + the recent post**.
- Narration: *"Everything posts to our own single brand account — no third-party or
  user-generated content."*

### Tools to record it
- **Screen capture:** the **`screenrecord`** skill (`~/.claude/skills/screenrecord/`) drives the
  live MCC and records the clickthrough; or the **`app-demo-video`** skill
  (`~/.claude/skills/app-demo-video/`) for an auto-highlighted, narrated walkthrough.
- **Narration voice:** the `use-voice` / `clone-voice` skill can generate the voiceover track.
- **Keep it under 50 MB:** export mp4 h264; if a single file is too big, split into ≤5 files by
  scene. (The 14 MB square DW promo already fits; a 106 MB reel would not.)

---

## 4. Exact submission steps (click-path)

1. Go to **developers.tiktok.com → Manage apps → DW Marketing**.
2. Select the **Production** view (top toggle) — NOT Sandbox. (Sandbox stays live and keeps
   working throughout review; you're submitting the production app for audit.)
3. **App details:** fill every field from **§1** and **upload the icon**. Save.
4. **Products:** ensure **Login Kit** and **Content Posting API** are both added.
5. **Scopes:** add `user.info.basic`, `video.publish`, `video.upload`.
6. **Redirect URI:** confirm `https://marketing.designerwallcoverings.com/api/channels/oauth/tiktok/callback`
   is registered under Login Kit.
7. **Scope-usage explanation:** paste the **§2** free-text into the "describe how your app uses
   each scope/product" field.
8. **Demo video:** attach the mp4(s) recorded per **§3**.
9. Click **Submit for review**.

**What happens next:**
- The app enters TikTok's **App Review queue** (typically a **few business days**; can be longer,
  and reviewers sometimes reply with a change request rather than an outright decision).
- **The sandbox keeps working the whole time** — you can keep posting `SELF_ONLY`/private test
  posts to @designerwallcoverings while the production app is under review.
- On **approval**, the production client key `aw1ccgi9nspzz8io` gains public `video.publish`, and
  @designerwallcoverings can be posted to **publicly** (account no longer has to be Private).
- If TikTok requests changes, address them and re-submit — the same package applies.

---

## 5. Pre-submission checklist

- [x] Domain `designerwallcoverings.com` verified in portal
- [x] Sandbox configured; real SELF_ONLY post proven end-to-end (publish_id `v_pub_file~v2-1.766506…`)
- [x] ToS URL 200 · Privacy URL 200 (verified this session)
- [x] App icon 1024×1024 present at `~/Desktop/Images/DW-TikTok-icon.png`
- [x] `postTikTok()` + OAuth callback live in the MCC (`modules/channels/index.js`)
- [x] Production field values drafted (§1) — paste-ready
- [x] Scope-usage reviewer text drafted (§2) — paste-ready
- [ ] Production App details filled + icon uploaded in portal *(Steve, in portal)*
- [ ] Products/scopes/redirect confirmed in portal *(Steve, in portal)*
- [ ] **Demo video recorded** per §3 (sandbox, domain matches, all 3 scopes shown) *(record step)*
- [ ] **Submit for review** clicked *(Steve — gated, customer-facing/identity)*

### What's already done vs what needs a human

**Done / paste-ready (this package):** every field value, the ≤120-char description, both verified
policy URLs, the exact scope-usage reviewer paragraph, the full demo shot-list, the click-path.
The posting pipeline is proven working, so the flow in the video is real, not mocked.

**Needs a human:**
1. **Record the demo video** (§3) — a screen-recording session against the live MCC; involves
   firing a real (private, `SELF_ONLY`) post while the account is toggled Private. This is a gated
   publish + a filming step, so it's done live, not autonomously. The `screenrecord` /
   `app-demo-video` skills drive the capture.
2. **Click "Submit for review"** in the TikTok portal — Steve-only (customer-facing / identity /
   irreversible submission). Filling the portal fields (§1/§2/§4) is also in-portal, Steve-driven.