Skip to content
Build 9234610

Carton Sizing — units per full middle carton

One question, one answer: for a given product, how many units are in a full middle carton (the inner case)? That number drives retailer B2B carton sizing (Camel prepack / B2B order build) and PopForge synthetic-order quantities.

Source of truth — NAV (authoritative)

The authoritative source is NAV — the [PopSockets Live$Item Unit of Measure] table. This page is a generated snapshot, not a hand-maintained list. Camel reads NAV live at runtime; this page and its machine-readable twin are derivations, regenerated by scripts/gen_carton_qty.py in the PopForge repo so they can't silently drift from NAV. Don't hand-edit the quantities here — fix NAV, then regenerate.

The rule

carton_qty = the 2nd-highest Qty-per-UoM among the UoM tiers that carry a GTIN — the barcoded tier directly below the master CASE.

NAV stores several Unit-of-Measure tiers per item (EACH, INNER PACK, INNER CASE, CASE, WMT PK2, …), each with a "quantity per UoM." On the common shape the master CASE is the highest tier and the carton we ship to retailers is the GTIN-barcoded tier just below it — so filtering to GTIN-barcoded tiers only and taking the 2nd-highest quantity lands on that carton. Gating on GTIN also discards NAV's junk placeholder tiers for free (artifact A below).

The positional rule is a heuristic, not a universal law — cross-check the model table

"2nd-highest barcoded tier" assumes the carton always sits below a master CASE. That holds for every current B2B and PopForge SKU, but it is not universal: where a model stores its carton at the top CASE tier with a smaller real tier beneath it (the MS POPCASE carton-at-CASE cohort — artifact B), the rule undershoots and returns the smaller tier (4 instead of 24). No purely-positional read generalizes. The authoritative answer to "what carton is this model?" is the model → qty table above; run the per-SKU tier read and the model table as cross-checks on each other, and treat any mismatch as a NAV-setup error to fix.

Model → carton qty (full map)

NAV's Product Model is a clean predictor of carton size — a small model → qty lookup sizes almost every model with one constant. The full vetted map, mirrored here from the gist CSV, is 49 models with a derivable carton qty plus 8 non-cartonable models (bulk / components / parts — no carton tier). 26 of the 49 ship retailer-B2B today; the other 23 were derived from the broader SKU universe (a 1,194-SKU master list + 1 yr of 940 history = 2,822 SKUs) for when they do.

At a glance: 40 is the most common carton, 24 next, POWERPACK alone at 12, and only the bare MAGSAFE model is mixed (24 and 40 — sized per-SKU). SKUs = how many SKUs carry that model in NAV; blank Notes = uniform qty, no tier issue.

Ships retailer-B2B today (26 models)

Model Carton qty SKUs Notes
MAGSAFE 24 / 40 143 Mixed — size per-SKU; model too coarse
POPGRIP 40 122
MS POPCASE AND SLIDE 24 41 Level drift + junk tiers — 24 at CASE and INNER PACK (artifacts A & B)
TOP AND CHAIN LITE 24 40
MAGSAFE POPWALLET+ 40 26
PLANT 40 20
KICK-OUT POPGRIP 40 11
MS KINDLE CASE 24 8
MAGSAFE POPWALLET+KO 24 6
POWERPACK 12 5
SUCK-UP POPGRIP 24 5
MS KICK-OUT BASE 24 4
POPWALLET+ 40 2
BACKSPIN 40 2
MAGSAFE POPWALLET 40 2
POPMOUNT FLEX 24 2
SLIDE INSERTS 24 2
WRISTLETS 40 2
POPWALLET 40 1
POPMOUNT DASH 24 1
POPMOUNT SURFACE 40 1
POPMOUNT VENT 40 1
SLIDE STRETCH 40 1
POPMOUNT MS VENT 24 1
POPMOUNT MS SURFACE 24 1
POPMOUNT2 SUCTION 24 1

Mapped, not yet shipping B2B (23 models)

Derived from the full NAV item master for when they ship retailer-B2B.

Model Carton qty SKUs Notes
POPTOP 40 58 ~98% consistent (2 SKUs show a different qty)
POPCASE AND SLIDE 24 30
SLIDE 40 28
POPPUCK STARTER KIT 24 23
STRAPS 24 13
SCREEN PROTECTOR 40 9
PHONE MOUNT LAPTOP 40 6
POPCASE 24 4
CAN HOLDER TALL 40 4
STASH 40 4
POPCHAIN 40 3
BOTTLE OPENER 40 3
ARPD HLR AND PCHN 40 3
LOW-PRO 24 3
MAGSAFE ADAPTER 40 2
CAN HOLDER 40 2
JUMPSTART 24 2
FIDGET TRAIN 40 1
CAN HOLDER SLIM 40 1
CUP SLEEVE 40 1
ARPD HLR PR AND PCHN 40 1
POPMOUNT2 PHOTO 40 1
GRIP AND VNT MNT 40 1

Non-cartonable (8 models — no carton tier)

Bulk packs, loose components and parts — no inner-case / case / inner-pack tier, so the rule correctly returns nothing. If one ever needs to ship B2B that's an ops decision, not something NAV can answer today.

BULK (17 SKUs) · POPPACK (7) · PLATFORM COMPONENT (6) · LIPS (6) · POCKETABLE PLATFORM (4) · POPPUCK BOOSTER PACK (2) · BULK CAN HOLDER (2) · COMPONENT (1)

Three real issues make a naïve "read one fixed UoM tier" rule unsafe. MAGSAFE is a sizing ambiguity; the other two — A (junk tiers) and B (level drift) — are NAV tier-storage artifacts that happen to co-occur on the same models. The robust read is barcoded tiers only, cross-checked against the model table — the two together, never either alone. All three are worth fixing at the NAV source.

MAGSAFE mixes 24 and 40 — and no NAV field separates them

The bare MAGSAFE model (143 SKUs) carries two carton sizes — most at 40 (standard slim grips) and ~22 at 24 — and no NAV category field distinguishes them (Model / Family / Category all read MAGSAFE / GRIPS for both). The 24s aren't a type; they're physically bulky items mixed in — the real BASE MSC bases plus oversized novelty grips (Plush Hello Kitty, Squishy Archie, Death Star, Resin Ring Pop, Airbag) plus a Costco 2-pack. The determinant lives in packaging, not category: a standard grip has a real inner-case = 40; every 24-packer has no inner-case tier. So MAGSAFE is sized per-SKUhas a barcoded inner-case → 40, else → 24 — never by model. (The named MAGSAFE POPWALLET+ / POPWALLET / POPWALLET+KO are separate, uniform models — 40 / 40 / 24 — not part of this mix.)

Artifact A — junk degenerate tiers (no GTIN), widespread

NAV carries placeholder UoM tiers with quantity 1 and no GTININNER CASE = 1, WMT PK2 = 1, WMT CS2 = 1 — observed directly on TOP AND CHAIN LITE and MS POPCASE AND SLIDE (and not unique to them). A rule that reads a tier by name — e.g. "read the INNER CASE tier" — returns 1. The GTIN filter skips these for free (they carry no barcode), which is exactly why the rule above is GTIN-gated. Live rows (prod NAV):

TOP AND CHAIN LITE 117116:  barcoded  EACH=1 · WMT CS2=12 · INNER PACK=24 · CASE=96
                            junk       INNER CASE=1 · WMT PK2=1                 (no GTIN)
TOP AND CHAIN LITE 807948:  barcoded  EACH=1 · INNER PACK=24 · CASE=96
                            junk       INNER CASE=1 · WMT CS2=1 · WMT PK2=1     (no GTIN)
MS POPCASE 112835–842:      barcoded  EACH=1 · INNER PACK=4 · CASE=24
                            junk       INNER CASE=1 · WMT CS2=1 · WMT PK2=1     (no GTIN)

Artifact B — carton qty stored at an inconsistent UoM level (level drift)

MS POPCASE AND SLIDE stores its real 24 carton at different levels across its SKUs: ~23 SKUs at the CASE (cs=24, with a smaller real INNER PACK=4 beneath) and ~18 newer ones at the INNER PACK (ip=24, with a cs=48 master above). No single positional read is right for both cohorts"read the CASE" returns 48 for the inner-pack cohort, while "2nd-highest barcoded tier" returns 4 for the carton-at-CASE cohort. Only the model table (MS POPCASE → 24) is authoritative here. A NAV data-hygiene item: same carton, inconsistent setup.

The robust read = barcoded tiers + model table

The per-SKU barcoded-tier rule sizes every current B2B and PopForge SKU correctly and discards junk (artifact A) for free, but it can't see through level drift (artifact B). Pair it with the model → qty table: derive per-SKU, compare to the model's expected qty, and flag mismatches as NAV-setup errors. That cross-check is what catches MS POPCASE before it ships wrong. (PopForge's gen_carton_qty.py uses this barcoded-tier rule — correct for all current PF SKUs, none of which are MS POPCASE — and the limitation is noted in the script.)

Retailer order policy

Carton size is a SKU property. How much a retailer orders per line is a separate, retailer property (from Kevin, 2026-06-16):

Retailer Orders in Per line
Target full cartons 1 inner case
Best Buy full cartons 1 inner case
Amazon eaches small per-unit quantities

PF test-SKU snapshot

Concrete examples pulled live from prod NAV on 2026-06-17 — the current twin snapshot:

SKU Model Description Carton qty Test use
800470 POPGRIP PG-Black-BK BK 40 Target
802693 POPMOUNT VENT PMNT2-G1-Vent-Black 40 Target
805136 POPGRIP PG-Clear-CLR CLR 40 Target / Amazon
805572 POPGRIP PG-Mama Bear-OW OW 40 Target
806290 POPGRIP PG-Lace Noir-(Gls)-BK BK 40 Target
117116 TOP AND CHAIN LITE CMB PT PCL-PKMN-…-Squishy Gengar Shadow Ball 24 Best Buy
807695 KICK-OUT POPGRIP PGKO MSC-Alum-Radial Silver-CLR SL 40 Best Buy
807948 TOP AND CHAIN LITE CMB PT PCL-Clear Glitter-CLRG 24 Best Buy
806827 MAGSAFE PG MSC-Clear-CLR CLR 40 Amazon (eaches)
806828 MAGSAFE PG MSC-Black-BK BK 40 NAV-direct default

Both MAGSAFE SKUs above land at 40 because they carry the barcoded inner-case tier — but MAGSAFE org-wide still spans 24 and 40, so it's always resolved per-SKU (see the MAGSAFE wrinkle). Don't read "MAGSAFE = 40" off this snapshot.

Machine-readable twin

The canonical machine-readable copy lives in the PopForge repo — this page and that file are siblings, both regenerated from NAV. Keep them in sync.

JSON shape:

{
  "skus": {                                  // per-SKU carton_qty (the PF test-SKU set today; regenerable to any SKU list)
    "806827": { "model": "MAGSAFE", "description": "PG MSC-Clear-CLR CLR", "carton_qty": 40 }
  },
  "retailer_order_policy": {                 // how each retailer orders (carton vs each)
    "target": { "unit": "carton" }, "bestbuy": { "unit": "carton" }, "amazon": { "unit": "each" }
  },
  "model_carton_qty": { "POPGRIP": 40, "TOP AND CHAIN LITE": 24 },   // model → qty rollup
  "model_rollup": {                          // model → { carton_qty, skus[], consistent } for drift detection
    "POPGRIP": { "carton_qty": 40, "skus": ["800470", "805136"], "consistent": true }
  }
}

To refresh: run scripts/gen_carton_qty.py against prod NAV and commit the diff (in the PopForge repo), then regenerate this page to match. Ping integrations/popforge for a fresh regen.


Per-SKU snapshot generated from NAV prod [PopSockets Live$Item Unit of Measure], 2026-06-17. The full model→carton map is mirrored from the gist CSV (prod NAV [PopSockets Live$Item] Product Model + UoM, crossed with 1 yr of retailer-B2B 940s). Source of truth is NAV; refresh the per-SKU set via gen_carton_qty.py (PopForge repo) and the model map from the gist — do not hand-edit values here.