shipped.json v1
Location
https://yourdomain/shipped.json, or /.well-known/shipped.json as a fallback. Your profile lives at /b/yourdomain.
No file? Any live domain still gets a record and a badge — the domain counts as one product. An Apple developer ID works the same way for apps. The file is how you add more.
Fields
| name | Display name. Optional, max 80 characters. Defaults to the domain. |
| apple | Apple developer IDs as strings. The number after /id on your App Store developer page. All apps under each ID are read automatically. |
| play | Android package names, e.g. com.yourcompany.app. Each one is read from its Play listing. |
| play_dev | Google Play developer names or numeric ids — the id in your developer page URL. Every app on that page is read, so you do not list packages one by one. |
| web | https URLs of products you say are live. |
| retired | Products you say are dead: an https URL, apple:<appId>, or play:<package>. |
| files | Public operating files — how you run things, what failed. Same domain as this profile, or a github.com/<o>/<r>/blob/… URL. Must serve as text/markdown or text/plain. The profile shows title, size, and date; it never mirrors the body. |
| telegram | Who may claim this record in the club: @username or a numeric Telegram id. The bot hands an invite only to the people named here. Whoever can edit the file owns the record. |
| github | owner/repo list. Stars, commit count, and last push are read from GitHub. Private or missing repos show as unavailable. |
Invalid entries are ignored one by one; the file still loads.
What gets verified, and how
- Apps — Apple Lookup API. Live count, names, icons, first release, last update. Storefronts checked: US, then KR.
- Android — each package's Play listing. A 200 means live, a 404 means gone. Name, icon, and "Updated on" are read from the page. Play publishes no release date, so Android never moves since or last ship.
- Web — we request each URL. A final 2xx means live. Anything else means down.
- Archive observation (web) — the first Wayback Machine capture is evidence of a domain observation, not a verified launch date for the current product. Web quick mode (no manifest) leaves since and last ship unconfirmed (
null). Archive observations are omitted when the archive is unreachable. - Retired — a URL must be down, an app must return zero results in every storefront. Otherwise it is shown as unverified and not counted.
What is not on the record
Followers. Self-reported revenue. Screenshots. Any date you type into the file. The file lists; third parties count.
Why so strict: across the builders we studied, self-reported revenue ran 1.6 to 5.6 times the payment-verified figure. A number we cannot check is not a smaller truth — it is a different kind of claim, and one bad one poisons every honest one next to it. So there is no field for it. Not labeled, not asterisked. Absent.
The one thing we cannot verify is omission. A product you never list never appears.
The badge
<a href="https://<site>/?from=yourdomain"><img src="https://<site>/badge/yourdomain" alt="Shipped" height="24"></a>A click lands on the SHIPPED homepage with your record at the top, so a curious visitor learns what the badge means. Add ?live=1 for your live count, ?theme=dark for dark footers. The badge never shows retired. Cached for an hour at the edge; changes to the file show within an hour.
Membership
One door, computed, never granted. You are a member while both hold:
- at least one live product, and
- third-party activity within the last 30 days: an App Store release or update, a Play "Updated on", or a GitHub push on a listed repo.
Miss the window and the lamp on your badge goes out — the badge keeps its color, it never turns grey. Ship an update and the lamp is back on the next render. Nobody decides; the dates do. Web-only records with no repo listed have no dated activity, so add a github repo to count. Nothing in shipped.json can set membership. See the emblems
The second due: one useful insight a week, posted in the group's Insights topic — at least 200 characters, title on the first line. The bot counts it (✍). Seven days without one: a reminder. Fourteen: you leave the group, same as dormancy. Insights are published on /inside unless the post starts with private.
The group
Members meet in a Telegram group called SHIPPED. The door is a bot, @shipped_gate_bot: send it /verify yourdomain.com (or your Apple developer ID). If the record says member, you get a one-use invite that expires in an hour. If it says dormant, the bot tells you what is missing.
Once a day the bot re-reads every member's record. Records with the lamp out are removed from the group and told why; ship an update and /verify again. The bot also posts yesterday's launches and updates from the stores. Inside: no channel promotion, no metrics rituals, no store-rating favors — the club pushes launches outward and members review each other's launches.
Public API
GET /api/record/<domain>
GET /api/record/apple/<developerId>JSON, schema: "shipped/1", CORS open, cached for an hour at the edge. Same numbers as the profile — summary, tier, apps, play, web, retired, plus profile_url and badge_url. Build on it.
Limits in v1
- Apple: one developer ID reads every app. Google Play:
play_devreads a developer page (first 50 apps);playadds single packages. Websites have no registry, so list each URL. - Sites that block automated requests may show as down. We retry with a browser user agent on 403, 405, and 429.
- The claim step is the file: the bot reads
telegramfresh on every/verify. An Apple-only record cannot be claimed; host ashipped.jsonon a domain you control.