Skip to content

ADR: Emergibles NFT Capability Improvements

Date: 2026-03-02 Status: Proposed Depends On: NFT Diamond Standard on Arbitrum, Miniapp Multi-Environment DeploymentDecision Makers: Architecture Team


Executive Summary

Emergibles is the user-facing NFT creation miniapp for Farcaster and Worldcoin audiences. Its current API surface (3 routes) is significantly thinner than the Monitor's NFT toolkit (25+ routes). This ADR defines targeted improvements to close the gap between what emergibles exposes to users and what the EmProps API backend actually supports, without turning emergibles into an admin tool.

Success Criteria: Users can complete a full NFT lifecycle — generate → configure → deploy → mint — from within the emergibles miniapp. Farcaster profile context is surfaced during creation. The app shares API infrastructure patterns with Monitor.


Context

Current State

Emergibles has three NFT API routes:

RoutePurpose
POST /api/nft/collections/generateAI-powered collection generation from prompt
PUT /api/nft/collections/[id]Update collection metadata/traits
POST /api/nft/collections/[id]/deploy-on-chainDeploy Diamond contract on-chain

The flow terminates at deploy. After a collection is deployed on-chain, users have no path to mint, no status visibility, and no way to share or discover tokens — they're left with a contract address.

What Monitor Has That Emergibles Doesn't

Comparing against Monitor's NFT routes that are user-relevant (not admin-only):

CapabilityMonitor RouteEmergiblesGap
Mint tokensPOST /api/nft/mintCritical — deploy without mint is incomplete
Generation statusGET /api/nft/mint + pollingJobs run async; users see no feedback
Metadata inspectionPOST /api/nft/metadataCan't preview ERC-721 metadata before deploy
Ownership checkPOST /api/nft/ownershipUsers can't verify their tokens
Farcaster PFPGET /api/neynar/pfpUser identity missing during creation
Chain selectionMulti-chain supportCurrently fully delegated to EmProps API
Payment flowN/A (admin tool)🚧 Stub/api/initiate-payment is a TODO

What Monitor Has That Emergibles Should NOT Adopt

Admin-only capabilities that belong in Monitor, not emergibles:

  • Collection reset/decommission
  • Admin deployer management
  • Bulk job management
  • Error pattern monitoring
  • Direct DB/Redis access

Architectural Observations

Both apps proxy to the same EmProps API with the same Authorization: Bearer ${EMPROPS_API_KEY} pattern. The API helper utilities (getApiUrl(), apiHeaders()) exist as inline code in emergibles rather than shared utilities. Monitor has a cleaner abstraction here.

Authentication divergence:

  • Emergibles: Worldcoin SIWE via NextAuth — good for Worldcoin MiniApp; limits Farcaster-native users
  • Monitor: Privy + Stack — admin-only, not appropriate for emergibles users

Decision

1. Complete the Mint Flow

Add /api/nft/mint to emergibles, mirroring Monitor's implementation but scoped to the authenticated user's collections only.

User Journey (completed):

Generate → Configure → Deploy → Mint → Success (with tokenId + media)

API route: POST /api/nft/collections/[id]/mint

  • Calls EmProps API /nft/collections/:id/mint
  • Requires session auth (user must own the collection)
  • Returns: { tokenId, jobId, estimatedCompletionMs }

Hook: useMintNftToken(collectionId) — React Query mutation

2. Add Generation Status Polling

NFT generation is asynchronous (ComfyUI job queue). Currently emergibles has no way to show progress after deploy-on-chain succeeds or after a mint is triggered.

Add: GET /api/nft/collections/[id]/status

  • Polls EmProps API for collection/job status
  • Returns: { status: 'pending' | 'generating' | 'complete' | 'failed', progress: number, tokenId? }

Hook: useNftCollectionStatus(collectionId) — React Query query with refetchInterval: 3000 while status !== 'complete'

This surfaces progress in the UI: a generation progress bar between deploy and the final success screen.

3. Farcaster Profile Context via Neynar

During collection creation, the user's Farcaster identity (PFP, username, FID) is available via the Farcaster miniapp SDK context. Currently this is used for auth but not surfaced meaningfully in the creation flow.

Add: GET /api/neynar/user (server-side)

  • Uses NEYNAR_API_KEY to fetch full Farcaster user data by FID
  • Returns: { username, displayName, pfpUrl, followerCount, bio }

Usage:

  • Pre-populate "creator profile" step in CreateStep.tsx with PFP + username
  • Pass social context into POST /api/nft/collections/generate payload to improve AI generation quality (Monitor already does this with social_identifiers)
  • Show creator attribution on the NftDeploySuccess.tsx screen

Environment variable needed: NEYNAR_API_KEY (add to env/components/emergibles.env)

4. Implement Payment Flow

/api/initiate-payment is a stubbed TODO. The payment model for emergibles is platform-custodial minting — users pay to mint, platform signs the transaction.

Decision: Implement payment as a pre-mint gate using the EmProps payment API.

Flow:

User clicks "Mint" → POST /api/initiate-payment → redirect/popup payment UI →
payment confirmed → POST /api/nft/collections/[id]/mint (server-side with platform wallet)

Initial implementation: World App Pay (MiniKit payment) for Worldcoin users, Farcaster's native payment channel for Farcaster-context users.

Defer: Stripe integration until explicitly needed outside miniapp contexts.

5. Extract Shared EmProps API Client

Both emergibles and Monitor inline the same proxy pattern. Create a shared utility in packages/ (or a shared module within apps) to avoid divergence.

Decision: Extract to apps/emergibles/src/lib/emprops-client.ts initially (same-app reuse). Promote to packages/emprops-client if Monitor or Studio need the same pattern.

typescript
// apps/emergibles/src/lib/emprops-client.ts
const BASE_URL = process.env.EMPROPS_API_BASE_URL;
const headers = () => ({
  'Authorization': `Bearer ${process.env.EMPROPS_API_KEY}`,
  'Content-Type': 'application/json',
});

export const empropsClient = {
  generateCollection: (payload) => fetch(`${BASE_URL}/nft/collections/generate`, { method: 'POST', headers: headers(), body: JSON.stringify(payload) }),
  updateCollection: (id, payload) => fetch(`${BASE_URL}/nft/collections/${id}`, { method: 'PUT', headers: headers(), body: JSON.stringify(payload) }),
  deployOnChain: (id, payload) => fetch(`${BASE_URL}/nft/collections/${id}/deploy-on-chain`, { method: 'POST', headers: headers(), body: JSON.stringify(payload) }),
  mintToken: (id, payload) => fetch(`${BASE_URL}/nft/collections/${id}/mint`, { method: 'POST', headers: headers(), body: JSON.stringify(payload) }),
  getStatus: (id) => fetch(`${BASE_URL}/nft/collections/${id}/status`, { headers: headers() }),
};

6. Auth: Add Farcaster Wallet Sign-In as Fallback

Emergibles currently requires Worldcoin MiniKit. In Farcaster frame contexts where Worldcoin isn't available, users can't authenticate.

Decision: Add Farcaster Sign-In with Ethereum (SIWF) as a second NextAuth provider alongside Worldcoin Credentials provider.

  • Uses @farcaster/auth-client (already in miniapp SDK)
  • Extends session with: { fid, username, pfpUrl } from verified Farcaster identity
  • Worldcoin remains primary; Farcaster SIWF is fallback for Farcaster-only contexts

Scope: Auth improvements in apps/emergibles/src/auth/ — no other apps affected.


Implementation Phases

Phase 1: Core Completion (P0 — deploy currently leads nowhere)

TaskFileEffort
Add mint routesrc/app/api/nft/collections/[id]/mint/route.tsSmall
Add status routesrc/app/api/nft/collections/[id]/status/route.tsSmall
Add useMintNftToken hooksrc/hooks/useMintNftToken.tsSmall
Add useNftCollectionStatus hooksrc/hooks/useNftCollectionStatus.tsSmall
Wire mint + status into UIPreviewStep.tsx, NftDeploySuccess.tsxMedium
Extract emprops clientsrc/lib/emprops-client.tsSmall

Phase 2: Identity & Payment (P1 — first impression and monetization)

TaskFileEffort
Add Neynar user routesrc/app/api/neynar/user/route.tsSmall
Pre-populate creator profile in CreateStepsrc/components/nft/CreateStep.tsxSmall
Implement payment initiationsrc/app/api/initiate-payment/route.tsMedium
Add NEYNAR_API_KEY to emergibles.envenv/components/emergibles.envTrivial

Phase 3: Auth Expansion (P2 — broader audience)

TaskFileEffort
Add Farcaster SIWF providersrc/auth/index.tsMedium
Update session typessrc/auth/types.tsSmall
Test Farcaster-context-only flowsManual + integrationMedium

Consequences

Positive

  • Complete user flow — generate → deploy → mint is now end-to-end
  • Identity-rich creation — Farcaster context improves AI generation quality and UX
  • Monetization unblocked — payment stub completed
  • Consistent API patterns — shared client reduces Monitor/Emergibles drift
  • Broader auth — Farcaster users without Worldcoin can participate

Negative

  • Neynar API key dependency — adds a new secret to manage per environment
  • More async complexity — status polling adds UI state for in-progress generation
  • Payment scope ambiguity — World App Pay vs other payment channels requires product decision

Not In Scope

  • Chain selection UI (emergibles stays EmProps-managed for simplicity)
  • Admin capabilities from Monitor (reset, decommission, deployer management)
  • Trait/token filtering (P3+)
  • Marketplace discovery within emergibles (separate product concern)

Alternatives Considered

1. Share Monitor's NFT Routes as a Package

Rejected. Monitor's routes include admin functionality (reset, decommission, bulk operations) that would be inappropriate to expose in a user-facing app. The right approach is purpose-built routes for emergibles that call the same EmProps API with appropriate auth scoping.

2. Replace Worldcoin Auth Entirely with Privy

Rejected. Emergibles is a Worldcoin miniapp first. Removing Worldcoin auth breaks the primary distribution channel. Adding Farcaster SIWF as a fallback is the additive approach.

3. Skip Phase 1 and Go Straight to Diamond Integration

Rejected. The current deploy-on-chain route doesn't support minting yet, so the Diamond integration gap is partly an emergibles gap. Phase 1 (mint + status) makes the current EmProps/Diamond infrastructure accessible to users without requiring further API backend changes.


Released under the MIT License.