# Seed existing subscribers When you connected Stripe, Crossdeck discovered your customers — but as rail-keyed records with no user ID yet. This step is the link: you tell Crossdeck which of your users owns which discovered customer. Source: https://cross-deck.com/university/seed-existing-subscribers/ Verified Crossdeck University lesson — prose plus real, runnable code. ## Crossdeck found your customers — now name them The rail discovery from move 1 gave Crossdeck a customer record for every Stripe customer it found — but each one is keyed only by its rail identity (a cus_…), with no developerUserId attached yet. Ready to be linked, but not yet linked. This step closes that gap: you read your own user table and tell Crossdeck, in one batched call, which user ID owns which rail customer. ## POST /v1/migration/users, in batches of 1000 From your backend (with your secret key), send up to 1,000 rows per request. Each row carries your developerUserId plus whatever you know — rail keys, traits, and the entitlements to backfill: ```web await fetch("https://api.cross-deck.com/v1/migration/users", { method: "POST", headers: { Authorization: `Bearer ${process.env.CROSSDECK_SECRET_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ users: [ { developerUserId: "user_847", // required email: "sam@example.com", stripeCustomerId: "cus_Nx…", // the rail key Crossdeck discovered entitlements: { pro: true }, // backfill current plan }, // …up to 1000 rows per request… ], }), }); ``` ## The rail-owned gate keeps you from double-granting Each row's developerUserId is matched to the rail-keyed customer Crossdeck discovered — via stripeCustomerId (or an Apple / Google key) — fusing the two into one canonical customer with both identities. That's the link. The clever part is what happens to the entitlements you assert. They pass a rail-owned gate, so you can safely send pro: true for everyone without fear of conflicting with the truth: The endpoint requires a secret key and rejects publishable ones with a clear message — this is a privileged, server-only operation. ## Rail customers, now linked to your users After the import runs, the customers Crossdeck discovered now carry your user IDs, and their plan is backfilled — live subscriptions deferring to the rail, manual grants only where there's no rail to defer to. Your existing book is now Crossdeck's, correctly. linked · plan backfilled cus_Nx… is now user_847, Pro — granted by the live Stripe subscription, not double-granted by the import.