00 / How to read thisConfidence is labelled. Don't skip it.
Pulled live from the Apify API on 28 Aug 2026 — actor IDs, per-event pricing, and 30-day success rates. These are measured, not quoted from a listing page.
Actor input schemas are not public — readable only with a token. Field names marked are the expected shape. Do not code against them until the real schema is read.
Model decision — locked
(a) Accept 2–4 week China→NZ ship times. No capital tied up, lower conversion. Every margin figure below therefore carries a refund provision, and the landing page must show an honest ETA. Under this model that provision is not optional — margin that ignores it is fiction.
Live test 28 Aug — the kill rule was wrong
The 1688 cost × 3.5 gate passes products that lose money. On the tested product (US$11.19 retail) the cheapest 1688 match was CNY 2.89 = NZ$0.68 — ×3.5 clears easily, yet the real net margin is −NZ$5.96. Product cost is nearly irrelevant: a 40× swing in supplier price moves net by NZ$27, while CAC and freight move it far more. The gate is now a US retail price floor, applied before the growth ranking. See S7.
01 / Stage detailWhat goes in, what comes out
Each stage names its API, its inputs, its outputs and where the result is stored. Amber stages spend money; green stages are logic we own and can build today.
Config
No API| In | APIFY_TOKEN, DATABASE_URL, FX rate, thresholds — MARGIN_MULTIPLE=3.5, KILL_SPEND_USD, KILL_CPA_NZD, REFUND_PROVISION_PCT |
|---|---|
| Out | — |
| Store | .env — never committed |
Discover
$0.0045/item · 2k ≈ $9Sweep TikTok Shop US by category. Runs on Apify's cloud with US proxies — this is why the NZ geo-block is irrelevant. It only ever blocked you, not the pipeline.
| API | unseenuser/TikTok-Shop-Scraper — 100% success / 10,197 runsPOST api.apify.com/v2/acts/{actor}/run-sync-get-dataset-items |
|---|---|
| In | category or keyword list · market US · maxItems |
| Out | mode enum shop_search·shop_catalog·product_details·product_reviews·creator_showcase · region US GB ID MY PH SG VN TH DE FR (no NZ) · getRelatedVideos — may return S3's videos itself, collapsing two stages |
| Store | upsert Product; append ProductSnapshot — never update |
The velocity trap
This response is cumulative lifetime units — "12.5k sold" says nothing about the last seven days. There is no trend in this data. Trending is a delta between two snapshots, which is the entire reason S2 exists and why snapshots are append-only.
Velocity
Free · oursThe one piece of genuine IP in the pipeline. Diff our own snapshot history rather than trusting an actor to compute it.
| In | ≥2 ProductSnapshot rows for the same productId |
|---|---|
| Out | units24h units7d growthPct7d velocityScore |
| Math | units7d = snap(t).unitsSoldTotal − snap(t−7d).unitsSoldTotal |
| Rank | Growth % off a low absolute base — not volume. A 50k-unit product is already saturated and its 1688 price is bid up. |
Cold start
Day one has no history, so this stage produces nothing until the second run. That is what S2b is for — and it is also why building the store comes before the analysis.
Cold-start bridge
$0.002 + $0.004 / productThe only actor that keeps its own daily history — so it has a trend on day one, while ours is still building.
| API | memo23/tiktok-shop-sales-scraper — 100% success |
|---|---|
| In | product URLs or IDs |
| Out | soldCount (cumulative) unitsSoldInWindow unitsSoldPerDay salesGrowthPercent trendWindowDays firstSeenAt — verified live |
| Proof | Ranked by cumulative: 136,585 units, 0.3% growth — dead. Ranked by growth: 71 units, 491.7% — just moving. Two different businesses, for 13 cents. |
| Trap | trendWindowDays is capped by their history depth — min 0.9 / mean 5.4 / max 6.9, all first seen within 8 days. Reject rows under 5 days; 491% over 0.9d is noise. |
| Then | Wean off it. lurkapi was the best-fitting actor in this category and went UNDER_MAINTENANCE mid-research. When an actor dies, our snapshot history is the only thing that survives. |
Creative capture
Per productThe hook that made the product trend is already public and already proven. Capture it here, while the product URL is in hand — not at S10 when you'd otherwise write ads cold.
| API | thenetaji/tiktok-shop-creator-videos-scraper — 100% / 163 runs |
|---|---|
| In | product URL |
| Out | every showcase + affiliate video promoting it — videoUrl creatorName followers views likes |
| Store | Creative → feeds S10 directly |
Shippability filter
Free · kills ~halfA pure text filter that costs nothing and runs before any sourcing spend. Never pay to source something that can't fly.
| In | Product.title · category · description |
|---|---|
| Out | shipVerdict: pass | reject + shipReasons[] |
| Rejects | lithium / battery (air freight) · liquids & aerosols · oversized · branded or counterfeit-risk · electricals needing NZ approval · dead-season |
Reverse-image source
$0.005 / resultThis is the bridge. It is the single step that turns "trending" into "sourceable" — everything upstream is signal, everything downstream is commerce.
| API | devcake/scraper-by-image — 100% / 11,911 runs |
|---|---|
| In | Product.imageUrl |
| Out | 30 matches, 50+ fields — price_min price_max moq sold_90d month_sold years_as_gold_supplier factory_inspected delivery_hours service_score |
| Gotchas | provider takes one value per run — all three platforms = 3 runs, 3× cost. maxProducts has a minimum of 30. Matches are a candidate set, not an identification — an LED-strip image also returned car ambient lights, so a relevance filter belongs before S7. |
| Store | SourceMatch — this returns so much supplier data it may make S6 partly redundant; re-scope S6 to finalists only |
Supplier enrichment
$0.005 + $0.003 / product| API | zen-studio/1688-wholesale-scraper — 9 failures / 35,357 runs |
|---|---|
| In | 1688 product URLs from S5 |
| Out | tiered wholesale pricing · MOQ · supplier verification · factory stats · dropship channels · certifications |
| Store | SourceMatch — enriched in place |
Margin gate
FX onlyThe gate is a number, not an availability check. Something being purchasable is not the same as it being worth buying.
| API | FX rate CNY→NZD — still to be chosen. Cache daily; never call per product. |
|---|---|
| In | unitCostCny · FX · freight/unit · target sell price · NZ GST 15% · Meta CAC estimate · refund provision |
| Out | landedCostNzd netMarginNzd marginPct marginVerdict |
| Math | net = sellNzd/1.15 − landedCost − metaCac − (sellNzd × refundProvision) |
| Kill | US retail price FLOOR — applied before the growth ranking. Freight (~NZ$6.50) and CAC are near-fixed per unit, so a cheap product cannot carry them. CAC NZ$6 → break-even US$12.00, 25% net at US$17.25 · CAC NZ$12 → break-even US$16.25, 25% net at US$23.50 · CAC NZ$18 → break-even US$20.75, 25% net at US$30.00 Working rule: US retail ≥ US$25. Under ~US$16 is structurally dead however well it trends. |
| Note | CAC and freight are estimates until the first real campaign — the table moves with them, but the shape holds. |
Human gate
Greg · weeklyOne list, once a week. Nothing past this point is free — this is the last stop before ad spend.
| In | Candidate where status = pending, ranked by velocityScore |
|---|---|
| Out | status → approved | rejected · decidedAt · decidedNote |
Landing page
Shopify Admin API| API | Shopify Admin API (product + page create), or SettledLoop for a single-product funnel |
|---|---|
| In | approved Candidate + Creative |
| Out | live URL |
| Must | Honest delivery ETA on the page. This is the model (a) tax — skipping it converts into chargebacks, not sales. |
Meta ads
Meta Marketing API| API | Meta Marketing API — campaign / adset / ad create |
|---|---|
| In | LP URL + Creative from S3 |
| Out | campaign + ad IDs |
| Reuse | meta-ads · meta-creative-engine · meta-ads-copy skills already exist — assembly, not greenfield |
Monitor
Meta Insights + Shopify Orders| API | Meta Insights (spend, CPA) + Shopify Orders (actual sales) |
|---|---|
| In | campaign IDs · KILL_SPEND_USD · KILL_CPA_NZD |
| Out | continue | kill |
Kill criteria set before spend
"Monitor" is not a stage until it carries a number. Kill at $X spend with zero purchases, or CPA > $Y. Without thresholds fixed in advance, monitoring is just watching it bleed.
Scale
DecisionWinners only — and this is where the model (b) question returns. Pre-buying a validated winner into NZ stock cuts delivery to three days and lifts conversion, but that is a capital decision taken per product, on evidence, not a strategy switch.
02 / InventoryEvery API, and what's blocking it
| API | Stages | Auth | Status |
|---|---|---|---|
| Apify — 5 actors | S1 · S2b · S3 · S5 · S6 | APIFY_TOKEN | No token — hard blocker |
| FX rate CNY→NZD | S7 | tbd | Not chosen |
| Shopify Admin | S9 · S11 | store token | Available — Coy precedent |
| Meta Marketing + Insights | S10 · S11 | existing access | Available |
The only hard blocker
The Apify token. Everything at S2, S4, S7 and S8 is internal logic that can be built and tested against fixtures right now — that is a third of the pipeline, and the third that holds the actual IP.