Bring your already-built app into Turtini (external-app listings)
You don't have to build inside Turtini's SDK to publish on the Marketplace. If you've already built an app — in Claude Code, on Vercel, on Cloudflare Pages, anywhere — you can register it as an external-app block. Turtini becomes a new distribution + monetization + identity channel for an app you already own.
Two kinds of listings:
• Bundle (.js) — you ship a single ES module built with defineMarketplaceBlock. Lives in Turtini Storage. Best for small, focused widgets.
• External app (https:// URL) — you point Turtini at a URL of an app you host wherever you like. Best when you've already built something polished and don't want to rewrite it for the SDK contract.
What changes between the two:
Nothing visible to the installing org. Both render in the same sandboxed iframe with the same capability gates. The host pipes the same init message in (data, viewer, capabilities, identityToken when granted), and your app calls the same postMessage RPCs back (fetch, submitLead, startCheckout, track). The only difference is whether the iframe loads a srcDoc wrapper that imports a bundle, or src= your URL directly.
To register an external app:
1. Submit a new listing as usual (org slug + block slug + label + pricing).
2. On the "Bundle or external app" phase, click "Register an external URL".
3. Paste the https:// URL where you host the embed entry point (e.g. https://my-app.dev/embed/widget).
4. Declare capabilities (only what you actually need — reviewers reject anything broader).
5. Submit for review.
Your app must implement the postMessage protocol:
window.addEventListener('message', e => {
if (e.data?.kind !== 'init') return
// e.data: { data, viewer, capabilities, blockId, version }
// Render your app using e.data.data as field input.
// To call back, postMessage to parent: { kind: 'fetch'|'submitLead'|'checkout'|'track', id, payload }
})
Security model (identical to bundle blocks):
The iframe runs with sandbox="allow-scripts" and NO allow-same-origin. Origin is opaque. You cannot read host cookies, localStorage, or DOM. Every fetch/submit/checkout you request goes through the platform's capability check before hitting the network.
Versioning:
External apps still semver. When you ship a new build at the same URL, bump the version number and resubmit. Installs that "trackLatest" pick up the new version automatically; pinned installers stay on theirs (note: external apps live behind a URL, so "pinning" really means "we declared version X was reviewed", not "we have a frozen artifact" — your responsibility to keep historical versions reachable or break those pinned installs).
Pricing + payouts:
Identical to bundle blocks. Free / one-time / subscription with 90/10 default rev share to your Stripe Connect account.
Real-world scenarios this enables:
• You spent 3 weeks in Claude Code building a polished testimonial carousel for your own site. List it on Turtini's Marketplace — every nonprofit, every restaurant, every property org can install it. You earn $X per install, your code never has to move.
• You run a productized service at an existing URL. Wrap an embed view in postMessage; nonprofits installing the block get an identity-bridged signup flow (their visitor's Turtini account folds into your user table via the identity.verify capability, no double signup).
• You're a developer who wants to ship fast: use Claude Code, host on Vercel, register the URL with Turtini, get distribution + monetization on day one.