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:
| Route | Purpose |
|---|---|
POST /api/nft/collections/generate | AI-powered collection generation from prompt |
PUT /api/nft/collections/[id] | Update collection metadata/traits |
POST /api/nft/collections/[id]/deploy-on-chain | Deploy 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):
| Capability | Monitor Route | Emergibles | Gap |
|---|---|---|---|
| Mint tokens | POST /api/nft/mint | ❌ | Critical — deploy without mint is incomplete |
| Generation status | GET /api/nft/mint + polling | ❌ | Jobs run async; users see no feedback |
| Metadata inspection | POST /api/nft/metadata | ❌ | Can't preview ERC-721 metadata before deploy |
| Ownership check | POST /api/nft/ownership | ❌ | Users can't verify their tokens |
| Farcaster PFP | GET /api/neynar/pfp | ❌ | User identity missing during creation |
| Chain selection | Multi-chain support | ❌ | Currently fully delegated to EmProps API |
| Payment flow | N/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_KEYto fetch full Farcaster user data by FID - Returns:
{ username, displayName, pfpUrl, followerCount, bio }
Usage:
- Pre-populate "creator profile" step in
CreateStep.tsxwith PFP + username - Pass social context into
POST /api/nft/collections/generatepayload to improve AI generation quality (Monitor already does this withsocial_identifiers) - Show creator attribution on the
NftDeploySuccess.tsxscreen
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.
// 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)
| Task | File | Effort |
|---|---|---|
| Add mint route | src/app/api/nft/collections/[id]/mint/route.ts | Small |
| Add status route | src/app/api/nft/collections/[id]/status/route.ts | Small |
Add useMintNftToken hook | src/hooks/useMintNftToken.ts | Small |
Add useNftCollectionStatus hook | src/hooks/useNftCollectionStatus.ts | Small |
| Wire mint + status into UI | PreviewStep.tsx, NftDeploySuccess.tsx | Medium |
| Extract emprops client | src/lib/emprops-client.ts | Small |
Phase 2: Identity & Payment (P1 — first impression and monetization)
| Task | File | Effort |
|---|---|---|
| Add Neynar user route | src/app/api/neynar/user/route.ts | Small |
| Pre-populate creator profile in CreateStep | src/components/nft/CreateStep.tsx | Small |
| Implement payment initiation | src/app/api/initiate-payment/route.ts | Medium |
Add NEYNAR_API_KEY to emergibles.env | env/components/emergibles.env | Trivial |
Phase 3: Auth Expansion (P2 — broader audience)
| Task | File | Effort |
|---|---|---|
| Add Farcaster SIWF provider | src/auth/index.ts | Medium |
| Update session types | src/auth/types.ts | Small |
| Test Farcaster-context-only flows | Manual + integration | Medium |
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.
Related Documentation
- NFT Diamond Standard on Arbitrum
- EmProps Studio NFT Revival
- Miniapp Multi-Environment Deployment
apps/emergibles/src/app/api/— Current API surfaceapps/monitor/src/app/api/nft/— Reference NFT implementation
