diff --git a/cspell.json b/cspell.json index 61daf8c..eeb5e11 100644 --- a/cspell.json +++ b/cspell.json @@ -43,6 +43,7 @@ "efgh", "erigon", "están", + "EURC", "Ethereum", "ethersproject", "fdir", @@ -167,6 +168,7 @@ "unlinkable", "unpackedProof", "urlencode", + "USDCE", "userop", "UUPS", "uvwx", @@ -176,7 +178,12 @@ "vuni", "wagmi", "walletauth", + "WBRL", + "WCLP", + "WCOP", "wcsep", + "WMXN", + "WPEN", "webview", "worldapp", "worldchain", diff --git a/mini-apps/commands/pay.mdx b/mini-apps/commands/pay.mdx index 4815917..4a98992 100644 --- a/mini-apps/commands/pay.mdx +++ b/mini-apps/commands/pay.mdx @@ -7,6 +7,22 @@ description: "Request a payment from the user" This command is an abstraction for a simple transfer. This shouldn't be used outside of World App. Pay supports WLD and all local stablecoins. +## Supported Tokens + +Import the `Tokens` enum instead of hardcoding symbol strings. Only `Tokens.USDC` has a value that differs from its name (`"USDCE"`): + +| `Tokens` member | Enum value | Currency | +| --- | --- | --- | +| `Tokens.WLD` | `"WLD"` | Worldcoin | +| `Tokens.USDC` | `"USDCE"` | USD Coin | +| `Tokens.EURC` | `"EURC"` | Euro Coin | +| `Tokens.WARS` | `"WARS"` | Argentine Peso stablecoin | +| `Tokens.WCOP` | `"WCOP"` | Colombian Peso stablecoin | +| `Tokens.WMXN` | `"WMXN"` | Mexican Peso stablecoin | +| `Tokens.WBRL` | `"WBRL"` | Brazilian Real stablecoin | +| `Tokens.WPEN` | `"WPEN"` | Peruvian Sol stablecoin | +| `Tokens.WCLP` | `"WCLP"` | Chilean Peso stablecoin | + ## Basic Usage @@ -15,9 +31,6 @@ import { MiniKit } from "@worldcoin/minikit-js"; import { Tokens, tokenToDecimals, - type CommandResultByVia, - type MiniKitPayOptions, - type PayResult, } from "@worldcoin/minikit-js/commands"; export async function sendPayment() { @@ -40,8 +53,7 @@ export async function sendPayment() { }, }; - const result: CommandResultByVia = - await MiniKit.pay(input); + const result = await MiniKit.pay(input); await fetch("/api/confirm-payment", { method: "POST", @@ -62,6 +74,7 @@ type MiniKitPayOptions = { token_amount: string; }[]; description: string; + network?: Network; // Optional; currently only "worldchain" and defaults to World Chain fallback?: () => unknown; }; ``` diff --git a/mini-apps/commands/request-permission.mdx b/mini-apps/commands/request-permission.mdx index 5ec66c4..b30b012 100644 --- a/mini-apps/commands/request-permission.mdx +++ b/mini-apps/commands/request-permission.mdx @@ -81,6 +81,8 @@ Define a custom fallback in the command payload for support outside mini apps. ## Error Codes +The SDK's `RequestPermissionErrorCodes` enum defines these errors: + | Code | Meaning | | --- | --- | | `user_rejected` | The user rejected the request | @@ -90,6 +92,8 @@ Define a custom fallback in the command payload for support outside mini apps. | `already_granted` | The permission is already granted | | `unsupported_permission` | The permission is not supported | +For microphone access, `permission_disabled` or `world_app_permission_not_enabled` means the user must first enable the microphone for World App; see the [microphone guide](/mini-apps/reference/microphone). The SDK types `world_app_permission_not_enabled` and `mini_app_permission_not_enabled` on the separate `MiniAppMicrophone` response event, not in `RequestPermissionErrorCodes`. + ## Preview
diff --git a/mini-apps/commands/send-transaction.mdx b/mini-apps/commands/send-transaction.mdx index dee6377..2d389dd 100644 --- a/mini-apps/commands/send-transaction.mdx +++ b/mini-apps/commands/send-transaction.mdx @@ -173,6 +173,10 @@ submitted, so the first identifier you receive is `userOpHash`. You can either use the `@worldcoin/minikit-react` hook or poll the Developer Portal to check when the user operation is mined and get the final `transaction_hash`. + +`poll()` rejects with `Error("Transaction failed")` only when the user operation's status is `failed`. Other rejections don't mean the transaction failed: a status request failed (HTTP or network error), the receipt wait failed or timed out, or polling stopped with an `AbortError` because you called `reset()`, the component unmounted, or a new `poll()` started. Status polling has no overall timeout (an unknown hash stays `pending`); the hook's `timeout` option only bounds the receipt wait once a transaction hash exists. Call `reset()` to stop polling. + + ```tsx title="React" import { useUserOperationReceipt } from "@worldcoin/minikit-react"; @@ -188,28 +192,63 @@ const { poll, isLoading, reset } = useUserOperationReceipt({ client }); const onClick = async () => { const result = await MiniKit.sendTransaction({...}); - const { receipt } = await poll(result.data.userOpHash); - // receipt contains the final transaction receipt + + try { + const { receipt } = await poll(result.data.userOpHash); + // receipt contains the final transaction receipt + } catch (error) { + if (error instanceof Error && error.message === "Transaction failed") { + // Only this error means the user operation failed + console.error("User operation failed"); + } else if (error instanceof Error && error.name === "AbortError") { + // Stopped by reset(), unmount, or a newer poll(); not a failure + } else { + // A status or receipt lookup failed; the outcome is unknown, so poll again + console.error("Could not confirm the user operation:", error); + } + } }; ``` ```ts title="API" -type UserOperationStatusSuccess = { - status: "success"; - userOpHash: string; - sender: string; - transaction_hash: string; - nonce: string; -}; +type UserOperationStatus = + | { + status: "pending"; + userOpHash: string; + sender: null; + transaction_hash: null; + nonce: null; + } + | { + status: "success"; + userOpHash: string; + sender: string; + transaction_hash: string; + nonce: string; + } + | { + status: "failed"; + userOpHash: string; + sender: string | null; + transaction_hash: string | null; + nonce: string | null; + }; const response = await fetch( `https://developer.world.org/api/v2/minikit/userop/${userOpHash}`, ); -const status = await response.json(); + +// The endpoint also returns 400/500 on a bad request or server error. +if (!response.ok) { + throw new Error(`Failed to fetch user operation status: ${response.status}`); +} + +const status: UserOperationStatus = await response.json(); if (status.status === "success") { - const success = status as UserOperationStatusSuccess; - console.log(success.transaction_hash); + console.log(status.transaction_hash); +} else if (status.status === "failed") { + console.error("User operation failed:", status.userOpHash); } ``` diff --git a/mini-apps/commands/share-contacts.mdx b/mini-apps/commands/share-contacts.mdx index db24bba..86db5ce 100644 --- a/mini-apps/commands/share-contacts.mdx +++ b/mini-apps/commands/share-contacts.mdx @@ -5,7 +5,7 @@ description: "Open the native contact picker using the unified MiniKit API." "twitter:image": "https://raw.githubusercontent.com/worldcoin/developer-docs/main/images/docs/docs-meta.png" --- -Use `MiniKit.shareContacts()` to open the World App contact picker. +Use `MiniKit.shareContacts()` to open the World App contact picker. The `getContacts` export from `@worldcoin/minikit-js/commands` is a legacy alias; call `MiniKit.shareContacts()` instead, since the standalone export never receives World App's response. ## Basic Usage diff --git a/mini-apps/commands/wallet-auth.mdx b/mini-apps/commands/wallet-auth.mdx index f35bb74..aa18af6 100644 --- a/mini-apps/commands/wallet-auth.mdx +++ b/mini-apps/commands/wallet-auth.mdx @@ -77,6 +77,7 @@ type WalletAuthResponse = address: string; message: string; signature: string; + version?: number; // Command protocol version (present when returned from World App) }; } | { @@ -91,7 +92,8 @@ type WalletAuthResponse = "data": { "address": "0x1234567890123456789012345678901234567890", "message": "example.com wants you to sign in with your Ethereum account", - "signature": "0xabcdef1234567890" + "signature": "0xabcdef1234567890", + "version": 2 } } ``` @@ -99,7 +101,7 @@ type WalletAuthResponse = ## Backend Verification -Always verify the returned SIWE payload on your backend. +Always verify the returned SIWE payload on your backend. This example targets Next.js 15+, where `cookies()` returns a `Promise`. ```ts import { cookies } from "next/headers"; @@ -115,7 +117,8 @@ type RequestBody = { export async function POST(req: NextRequest) { const { payload, nonce } = (await req.json()) as RequestBody; - if (nonce !== cookies().get("siwe")?.value) { + const cookieStore = await cookies(); + if (nonce !== cookieStore.get("siwe")?.value) { return NextResponse.json( { isValid: false, error: "Invalid nonce" }, { status: 400 }, @@ -157,7 +160,7 @@ export async function POST(req: NextRequest) { | `expirationTime` | `Date` | No | When the SIWE message expires | | `notBefore` | `Date` | No | SIWE message is not valid before this time | | `requestId` | `string` | No | Arbitrary ID for correlating the request on your backend | -| `fallback` | `() => Promise` | No | Custom fallback for non-World-App environments | +| `fallback` | `() => unknown` | No | Custom fallback for non-World-App environments (sync or async) | ## Notes diff --git a/mini-apps/growth/invites-viral.mdx b/mini-apps/growth/invites-viral.mdx index 01efed1..0535ef5 100644 --- a/mini-apps/growth/invites-viral.mdx +++ b/mini-apps/growth/invites-viral.mdx @@ -14,12 +14,16 @@ Referral programs are proven growth drivers because they leverage trust. People Create server-side invite pages that work across all platforms: -```typescript +```tsx // pages/invite.tsx +import { useEffect } from "react"; + +const appId = process.env.NEXT_PUBLIC_APP_ID; + export default function InvitePage({ code }: { code: string }) { useEffect(() => { // Redirect to mini app - window.location.href = `https://world.org/mini-app?app_id=${YOUR_APP_ID}&path=/invite?code=${code}` + window.location.href = `https://world.org/mini-app?app_id=${appId}&path=${encodeURIComponent(`/invite?code=${code}`)}` }, [code]) return
Redirecting to mini app...
@@ -34,7 +38,7 @@ Deep-link (opens World App directly if installed) `worldapp://mini-app?app_id={app_id}&path={path}` -To force opening in the device browser instead of the native webview, append `open_out_of_window=true` to the URL (works for both universal and deep links). +To open a link from your mini app in the device browser instead of World App, add `open_out_of_window=true` to its URL, e.g. `window.open("https://example.com/?open_out_of_window=true", "_blank")`. Note: path should be URL encoded. ### 2. Generate Share Links @@ -53,7 +57,7 @@ function generateInviteLink(userId: string): string { ### 3. Implement Share Functionality -Add share buttons at key moments in your user journey: +Add share buttons at key moments in your user journey. `trackEvent` below is a placeholder for your own analytics tool (Segment, PostHog, etc.), not a MiniKit command. ```typescript import { MiniKit } from "@worldcoin/minikit-js"; @@ -87,7 +91,7 @@ Process referral codes when new users sign up: // On app initialization function handleReferral() { const urlParams = new URLSearchParams(window.location.search); - const refCode = urlParams.get("ref"); + const refCode = urlParams.get("code"); if (refCode && !currentUser.referredBy) { // Credit the referrer @@ -107,28 +111,52 @@ function handleReferral() { Implement two-sided rewards that benefit both parties: +Requires a World-ID-verified user (an [IDKit](/world-id/idkit/integrate) proof, not [Wallet Auth](/mini-apps/commands/wallet-auth) — SIWE only proves wallet control, not personhood, so gating on it alone lets one person collect the bonus from many wallets). Never trust `newUserId`/`referrerCode` from an unauthenticated request, and claim the referral atomically so concurrent requests can't double-credit it: + ```typescript // api/process-referral.ts export async function processReferral(data: { newUserId: string; referrerCode: string; }) { + // Require a stored World ID nullifier for newUserId, set when they verified + // with IDKit — not a Wallet Auth session, which only proves wallet control. + if (!(await hasVerifiedWorldId(data.newUserId))) { + return { success: false, reason: "unverified_user" }; + } + const referrer = await getUserByCode(data.referrerCode); if (!referrer) { return { success: false, reason: "invalid_referrer" }; } - // Credit both users + if (referrer.id === data.newUserId) { + return { success: false, reason: "self_referral" }; + } + + // Atomically claim the referral (e.g. INSERT ... ON CONFLICT DO NOTHING on + // a unique referred_user_id column), then read back the stored referrer. If + // two requests race, only one INSERT succeeds. + const claimedBy = await claimReferral(data.newUserId, referrer.id); + if (claimedBy !== referrer.id) { + return { success: false, reason: "already_referred" }; + } + + // Credit both users. Each credit has its own idempotency key (unique in your + // credits table; treat a duplicate as success), so retrying processReferral + // after a partial failure writes only the missing credit. await Promise.all([ creditUser(referrer.id, { type: "referral_bonus", amount: 100, reason: "Friend joined via your invite", + idempotencyKey: `referral:${data.newUserId}:referrer`, }), creditUser(data.newUserId, { type: "signup_bonus", amount: 50, reason: "Welcome bonus for joining via invite", + idempotencyKey: `referral:${data.newUserId}:referee`, }), ]); @@ -200,6 +228,10 @@ const events = { }; ``` + +If you use the canonical [Core Event Set](/mini-apps/growth/analytics#2-%C2%B7-core-event-set-6-lines-of-code), `invite_link_created` maps to `invite_sent` and `signup_source_invite` maps to `invite_accepted`; `invite_link_clicked` has no equivalent there. Pick one taxonomy and use it consistently. + + ### Key Metrics Dashboard - **Invite Conversion Rate**: (Signups from invites) / (Total invite links clicked) @@ -225,6 +257,6 @@ Test these variables to optimize your viral loop: 1. Implement universal links for your invite flow 2. Add share buttons after key user achievements -3. Set up two-sided rewards with World ID verification +3. Set up two-sided rewards with World ID verification, self-referral, and idempotency checks 4. Track invite metrics and run small A/B tests 5. Scale successful invite mechanics across more touchpoints diff --git a/mini-apps/growth/notifications.mdx b/mini-apps/growth/notifications.mdx index 9816a1d..365a46a 100644 --- a/mini-apps/growth/notifications.mdx +++ b/mini-apps/growth/notifications.mdx @@ -12,21 +12,21 @@ Thoughtful, behavior‑based notifications keep users engaged long after they cl | -------------------- | ------------------------------------------------------------------- | | **Retention boost** | Targeted pushes can 2–3× day‑7 retention. | | **Free visibility** | ≥ 15 % open rate unlocks a persistent badge on your app icon. | -| **Strict standards** | < 10 % open = delivery paused for 7 days—quality is non‑negotiable. | +| **Strict standards** | < 15 % open = no home‑screen badge—quality is non‑negotiable. | ### 2 · Quality Thresholds | Open‑Rate (7‑day) | Platform Action | Your Next Step | | ----------------- | ----------------- | --------------------------------- | -| **< 10%** | Paused for 1 week | Audit triggers & copy immediately | -| **10%+** | Badge displayed | Maintain & iterate | +| **< 15%** | No badge | Audit triggers & copy immediately | +| **15%+** | Badge displayed | Maintain & iterate | | **25%+** | "Excellent" tier | Scale what works, test new ideas | ### 3 · Core Principles 1. **Trigger‑based > Broadcasts** – React to _user actions_ (wins, risks) instead of fixed schedules. 2. **Personalize** – Use `${username}` placeholder to personalize notifications with usernames. -3. **Copy rules** – ≤ 30‑char title, 1–2 emojis, clear value + curiosity gap. +3. **Copy rules** – ≤ 30‑char title, ≤ 200‑char message, 1–2 emojis, clear value + curiosity gap. ### 4 · Trigger Library @@ -45,6 +45,7 @@ Thoughtful, behavior‑based notifications keep users engaged long after they cl ### 6 · Copy Cheatsheet +- **Limits**: title ≤ 30 characters (≤ 16 plus `${username}` if you use it), message ≤ 200 characters (API-enforced). - **Lead with benefit**: "Earn 50 coins" beats "Check the app". - **Curiosity**: "Something new awaits …". - **Concrete numbers**: "30 s left" > "Hurry up". diff --git a/mini-apps/guidelines/app-guidelines.mdx b/mini-apps/guidelines/app-guidelines.mdx index 33bae64..ebca55c 100644 --- a/mini-apps/guidelines/app-guidelines.mdx +++ b/mini-apps/guidelines/app-guidelines.mdx @@ -179,7 +179,4 @@ npm install @worldcoin/mini-apps-ui-kit-react Learn more in the package README and Storybook: - [Package README](https://www.npmjs.com/package/@worldcoin/mini-apps-ui-kit-react?activeTab=readme) - href="https://www.npmjs.com/package/@worldcoin/mini-apps-ui-kit-react?activeTab=readme" - target="\_blank" - > Package README - [UI Kit Storybook](https://mini-apps-ui-kit.world.org) diff --git a/mini-apps/guidelines/features-and-guidelines.mdx b/mini-apps/guidelines/features-and-guidelines.mdx index 35c8017..e02c8c1 100644 --- a/mini-apps/guidelines/features-and-guidelines.mdx +++ b/mini-apps/guidelines/features-and-guidelines.mdx @@ -30,7 +30,7 @@ curl -X POST "https://developer.worldcoin.org/api/v2/minikit/send-notification" { "language": "en", "title": "title", - "message": "🧑‍🍳 We're cooking something special for you ${username}" + "message": "🧑‍🍳 We'\''re cooking something special for you ${username}" } ], "mini_app_path": "worldapp://mini-app?app_id=[app_id]&path=[path]" diff --git a/mini-apps/migration/standalone-dapp.mdx b/mini-apps/migration/standalone-dapp.mdx index c4a2485..4c325e0 100644 --- a/mini-apps/migration/standalone-dapp.mdx +++ b/mini-apps/migration/standalone-dapp.mdx @@ -18,7 +18,7 @@ MiniKit commands auto-detect the environment. Outside World App, they fall back ## Ask an agent Add this skill and ask your agent to convert your web app to a mini app using the steps outlined in this guide. ``` -npx skills add worldcoin/minikit-js miniapp-to-web +npx skills add worldcoin/minikit-js -s miniapp-to-web ``` ## 1. Install Dependencies @@ -85,7 +85,7 @@ export default function Providers({ children }: { children: React.ReactNode }) { ## World ID -No changes. [IDKit](https://docs.worldcoin.org/world-id/quick-start) is independent of the wallet layer. +No changes. [IDKit](/world-id/idkit/mini-apps) is independent of the wallet layer. ## Auth diff --git a/mini-apps/migration/web-to-miniapp.mdx b/mini-apps/migration/web-to-miniapp.mdx index 41db4c1..aad8494 100644 --- a/mini-apps/migration/web-to-miniapp.mdx +++ b/mini-apps/migration/web-to-miniapp.mdx @@ -10,7 +10,7 @@ Convert an existing Next.js web app that uses viem to work as a World App mini a ## Ask an agent Add this skill and ask your agent to convert your web app to a mini app using the steps outlined in this guide. ``` -npx skills add worldcoin/minikit-js web-to-miniapp +npx skills add worldcoin/minikit-js -s web-to-miniapp ``` ## 1. Install MiniKit diff --git a/mini-apps/more/community-tools-perks.mdx b/mini-apps/more/community-tools-perks.mdx index d83ec6e..fa2e228 100644 --- a/mini-apps/more/community-tools-perks.mdx +++ b/mini-apps/more/community-tools-perks.mdx @@ -8,12 +8,12 @@ Special perks and integrations from trusted providers supporting the World Mini - Pilot program rewarding qualifying Mini App developers based on verified - human usage. $300K USD equivalent in WLD over three months. + Ongoing rewards program for Mini App builders based on verified human + usage. Your Mini App must already be live in World App to apply. Foundation Grants supporting the World Network and novel mini apps (50M WLD diff --git a/mini-apps/quick-start/init.mdx b/mini-apps/quick-start/init.mdx index 0208eec..fd30fdb 100644 --- a/mini-apps/quick-start/init.mdx +++ b/mini-apps/quick-start/init.mdx @@ -75,8 +75,8 @@ import { MiniKit } from "@worldcoin/minikit-js"; import type { MiniAppGetPermissionsSuccessPayload } from "@worldcoin/minikit-js/commands"; const result = await MiniKit.getPermissions(); -const permissions: MiniAppGetPermissionsSuccessPayload["permissions"] = - result.data.permissions; +const permissions = (result.data as MiniAppGetPermissionsSuccessPayload) + .permissions; ``` Notes: @@ -117,6 +117,25 @@ MiniKit normalizes the raw World App launch origin into: If you need the untransformed World App payload, read `window.WorldApp` directly. + +`@worldcoin/minikit-js` doesn't ship a `Window.WorldApp` type. Declare it yourself in a `global.d.ts` file, matching the shape below: + +```tsx +export {}; // required so this file is a module and `declare global` is valid + +declare global { + interface Window { + WorldApp?: { + world_app_version: number; + device_os: "ios" | "android"; + // ...see the full shape in the Type tab below + [key: string]: unknown; + }; + } +} +``` + + ```tsx diff --git a/mini-apps/quick-start/installing.mdx b/mini-apps/quick-start/installing.mdx index e5d6884..9115e4e 100644 --- a/mini-apps/quick-start/installing.mdx +++ b/mini-apps/quick-start/installing.mdx @@ -10,7 +10,7 @@ description: "Create a Mini App with the official template or install MiniKit-JS ## Quick Start The fastest way to get started is by using our template next-15 repository. -Run the following command and follow the instructions to create a new mini app. For cleanliness we recommend using `pnpm` as your package manager. +Run the following command and follow the instructions to create a new mini app. This installs dependencies with `npm`; to use `pnpm`, add `--no-install` and run `pnpm install` in the new directory. ```bash npx @worldcoin/create-mini-app@latest my-first-mini-app @@ -48,6 +48,10 @@ pnpm install @worldcoin/minikit-js ``` + +**TypeScript**: the package's type declarations reference `window.WorldApp` without declaring it, so type-checking fails with `"skipLibCheck": false`. Set `"skipLibCheck": true` in `tsconfig.json` (the Next.js default), or add the [`Window.WorldApp` declaration](/mini-apps/quick-start/init#raw-world-app-object). + + ## Usage 1. Wrap your app with `MiniKitProvider` in a client component. This initializes MiniKit and makes it available throughout your app. @@ -93,6 +97,20 @@ import { MiniKit } from "@worldcoin/minikit-js"; console.log(MiniKit.isInstalled()); ``` +In a React component, you can read this reactively with the `useMiniKit()` hook, as the official starter template does: + +```tsx +import { useMiniKit } from "@worldcoin/minikit-js/minikit-provider"; + +export function MiniKitStatus() { + const { isInstalled } = useMiniKit(); + + if (!isInstalled) return null; + + return MiniKit is installed; +} +``` + ## Build with AI The [World Docs MCP](/model-context-protocol/world-docs) lets any coding assistant search the World documentation to help you build your mini app. @@ -100,12 +118,13 @@ The [World Docs MCP](/model-context-protocol/world-docs) lets any coding assista ```bash - claude mcp add --transport http world https://docs.world.org/mcp + claude mcp add --transport http --scope project world-docs https://docs.world.org/mcp ``` + `--scope project` writes a shareable `.mcp.json` to your project (recommended). Without it, the server is added only for you in this project (stored in `~/.claude.json`); use `--scope user` to add it to all your projects. ```bash - codex mcp add --transport http world https://docs.world.org/mcp + codex mcp add world-docs --url https://docs.world.org/mcp ``` @@ -113,7 +132,7 @@ The [World Docs MCP](/model-context-protocol/world-docs) lets any coding assista ```json { "mcpServers": { - "world": { + "world-docs": { "url": "https://docs.world.org/mcp" } } @@ -125,7 +144,7 @@ The [World Docs MCP](/model-context-protocol/world-docs) lets any coding assista ```json { "servers": { - "world": { + "world-docs": { "type": "http", "url": "https://docs.world.org/mcp" } diff --git a/mini-apps/quick-start/responses.mdx b/mini-apps/quick-start/responses.mdx index d314aab..1e8c123 100644 --- a/mini-apps/quick-start/responses.mdx +++ b/mini-apps/quick-start/responses.mdx @@ -21,7 +21,7 @@ import type { async function signInWithWallet() { const input = { - nonce: "random-nonce-123", + nonce: "exampleNonce123", } satisfies MiniKitWalletAuthOptions; try { @@ -48,5 +48,22 @@ async function signInWithWallet() { ## Event Subscriptions -For new 2.x command integrations, prefer `await MiniKit.()`. +For new 2.x command integrations, prefer `await MiniKit.()`; it resolves (or throws) directly, no event listener needed. +MiniKit also exposes a lower-level event API with one handler per response event. A new subscription replaces the previous handler. Use it only when managing the low-level response flow yourself: + +```tsx +import { MiniKit } from "@worldcoin/minikit-js"; +import { ResponseEvent } from "@worldcoin/minikit-js/commands"; + +MiniKit.subscribe(ResponseEvent.MiniAppWalletAuth, (payload) => { + console.log(payload); +}); + +// Later, to stop listening: +MiniKit.unsubscribe(ResponseEvent.MiniAppWalletAuth); +``` + +Commands register their response handlers with the same event manager. Do not use subscriptions to observe a concurrent `MiniKit.()` call: registrations can replace each other, and unsubscribing can prevent the command promise from resolving. Handle the awaited result instead. + +`MiniKit.trigger(event, payload)` invokes the event's current handler manually, mainly for testing. diff --git a/mini-apps/quick-start/testing.mdx b/mini-apps/quick-start/testing.mdx index 24dc3d4..f380a0f 100644 --- a/mini-apps/quick-start/testing.mdx +++ b/mini-apps/quick-start/testing.mdx @@ -25,11 +25,11 @@ Your app id is in the developer portal in the format `app_xxxxxxxxxx`. */} - + - To test on a phone, open `https://worldcoin.org/mini-app?app_id=` (the docs page renders this link as a scannable QR code): + To test on a phone, open `https://world.org/mini-app?app_id=` (the docs page renders this link as a scannable QR code): 1. Build the URL with your App ID from the developer portal. 2. Scan the QR (or open the URL) with your phone’s camera. diff --git a/mini-apps/reference/address-book.mdx b/mini-apps/reference/address-book.mdx index 40c3084..bee7185 100644 --- a/mini-apps/reference/address-book.mdx +++ b/mini-apps/reference/address-book.mdx @@ -23,8 +23,7 @@ const userWalletAddress = "0x000000000000000000000000000000000000dEaD" const isUserVerified = await getIsUserVerified(userWalletAddress) // optionally you can provide your rpc url as a second argument to the function ``` - Returns `true` if the address is verified -- Returns `false` if the address is not verified -- Throws an error if the verification check fails +- Returns `false` if the address is not verified, or if the check itself fails (errors are caught and logged, not thrown) ## React Bindings diff --git a/mini-apps/reference/credit-api.mdx b/mini-apps/reference/credit-api.mdx index c6313ce..12d57a7 100644 --- a/mini-apps/reference/credit-api.mdx +++ b/mini-apps/reference/credit-api.mdx @@ -19,6 +19,10 @@ https://credit.cash/api/borrower/[identifier] where `[identifier]` is either the user's wallet address or [World username](/mini-apps/reference/usernames). + +This endpoint requires authorization; unauthenticated requests, including the example below, receive `401 Unauthorized`. Contact the [Credit team](#support) for access before integrating. + + The response is a JSON object with two keys: - `state`: the user's status on Credit @@ -80,6 +84,7 @@ curl -s "https://credit.cash/api/borrower/0x764C890E7D96481cBEa64c64C0F9cFF34bFF | **Status** | **Error** | **Description** | | ---------- | --------------------------- | -------------------------------------- | | 400 | Missing identifier | No wallet address or username provided | +| 401 | Unauthorized | Missing or invalid authorization | | 404 | Username not found | World username could not be resolved | | 500 | Failed to get borrower info | Internal server error | diff --git a/mini-apps/reference/status-page.mdx b/mini-apps/reference/status-page.mdx index dd714bb..adb510c 100644 --- a/mini-apps/reference/status-page.mdx +++ b/mini-apps/reference/status-page.mdx @@ -18,7 +18,7 @@ For transactions, status is determined by: ## Get Status - https://status.worldcoin.org/api/services + https://status.world.org/api/services This endpoint returns the current status of all World services. @@ -31,11 +31,11 @@ This endpoint returns the current status of all World services. ```bash cURL -curl -X GET "https://status.worldcoin.org/api/services?logs=true" +curl -X GET "https://status.world.org/api/services?logs=true" ``` ```javascript -fetch('https://status.worldcoin.org/api/services?logs=true') +fetch('https://status.world.org/api/services?logs=true') ``` diff --git a/mini-apps/reference/usernames.mdx b/mini-apps/reference/usernames.mdx index 1eb566c..3b4c7af 100644 --- a/mini-apps/reference/usernames.mdx +++ b/mini-apps/reference/usernames.mdx @@ -25,4 +25,23 @@ Or you can request it manually, using the `getUserByAddress` method on MiniKit: const worldIdUser = await MiniKit.getUserByAddress(userAddress) ``` -Other ways involve querying the [usernames service](https://usernames.worldcoin.org/docs). \ No newline at end of file +You can also look a user up by their username with `getUserByUsername`: + +```tsx +const worldIdUser = await MiniKit.getUserByUsername(username) +``` + +Both methods return an object with `walletAddress`, `username`, and `profilePictureUrl` properties. The SDK type marks `username` and `profilePictureUrl` as optional; callers must also handle `null` profile values at runtime. + + +The two lookup methods handle unknown users differently: + +- `getUserByAddress(address)` preserves the supplied `walletAddress`. When the service returns no profile, `username` and `profilePictureUrl` are `null`. +- `getUserByUsername(username)` maps the service's unknown-user 404 response to an object whose properties are `undefined`. + +Check for a username before using profile data; a truthy `walletAddress` alone does not mean a profile exists. These unknown-user responses resolve normally, but network or JSON parsing failures can still reject the promise. + + +`MiniKit.getUserInfo` is also available as an alias of `getUserByAddress` (same signature, same behavior). + +Other ways involve querying the [usernames service](https://usernames.worldcoin.org/docs). diff --git a/mini-apps/sharing/add-money-qa.mdx b/mini-apps/sharing/add-money-qa.mdx index 1876cb6..43684a0 100644 --- a/mini-apps/sharing/add-money-qa.mdx +++ b/mini-apps/sharing/add-money-qa.mdx @@ -55,11 +55,11 @@ Url follows the schema below. Navigate there to use this Quick Action. ``` https://worldcoin.org/mini-app?app_id=app_e7d27c5ce2234e00558776f227f791ef -&path={%2Fbridge} -&toAddress={0xRecipientAddressHere} -&toToken={0xUSDCOrWLDAddress} -&amountUsd={100} -&sourceAppId={app_source1234567890abcdef} -&sourceAppName={My%20App} -&sourceDeeplinkPath={%2Fdashboard} +&path=%2Fbridge +&toAddress=0xRecipientAddressHere +&toToken=0xUSDCOrWLDAddress +&amountUsd=100 +&sourceAppId=app_source1234567890abcdef +&sourceAppName=My%20App +&sourceDeeplinkPath=%2Fdashboard ``` diff --git a/mini-apps/sharing/dna-qa.mdx b/mini-apps/sharing/dna-qa.mdx index 0dad6f3..02bb2cc 100644 --- a/mini-apps/sharing/dna-qa.mdx +++ b/mini-apps/sharing/dna-qa.mdx @@ -118,6 +118,7 @@ A string representing the complete deeplink URL to the DNA application with the ```typescript const deeplinkUrl = getDNADeeplinkUrl({ + tab: "send", fromToken: "0x79A02482A880bCE3F13e09Da970dC34db4CD24d1", toToken: "0x4200000000000000000000000000000000000006", recipientAddress: "0xRecipientAddressHere", @@ -131,7 +132,7 @@ console.log(deeplinkUrl); ## **Generated Deeplink URL:** ```bash -https://worldcoin.org/mini-app?app_id=app_8e407cfbae7ae51c19b07faff837aeeb&path=%2Fwallet%3Ftab%3Dsend%26fromToken%3D0x79A02482A880bCE3F13e09Da970dC34db4CD24d1%26amount%3D1234500%26toToken%3D0x4200000000000000000000000000000000000006%26recipientAddress%3D0xRecipientAddressHere%26sourceAppId%3Dapp_a4f7f3e62c1de0b9490a5260cb390b56%26sourceDeeplinkPath%3D%252Fsome%252Fpath +https://worldcoin.org/mini-app?app_id=app_8e407cfbae7ae51c19b07faff837aeeb&path=%2Fwallet%3Ftab%3Dsend%26fromToken%3D0x79A02482A880bCE3F13e09Da970dC34db4CD24d1%26amount%3D1235%26toToken%3D0x4200000000000000000000000000000000000006%26recipientAddress%3D0xRecipientAddressHere%26sourceAppId%3Dapp_a4f7f3e62c1de0b9490a5260cb390b56%26sourceDeeplinkPath%3D%252Fpath ``` ## **Note** diff --git a/mini-apps/sharing/sage-qa.mdx b/mini-apps/sharing/sage-qa.mdx index 0ba8aaf..0188535 100644 --- a/mini-apps/sharing/sage-qa.mdx +++ b/mini-apps/sharing/sage-qa.mdx @@ -4,6 +4,10 @@ title: "Sage Support" "twitter:image": "https://raw.githubusercontent.com/worldcoin/developer-docs/main/images/docs/docs-meta.png" --- + +The [Sage Developer dashboard](https://dev-dashboard-gamma.vercel.app) is unavailable, so the steps below can't be completed. + + [Sage](https://worldcoin.org/ecosystem/app_5dee2f19cd6eef599eb6ab275a0a7523) is an AI chatbot that lets users ask questions and get answers. Sage Support enables developers to integrate Sage chats seamlessly into their World Mini Apps. Developers get a white label version of Sage that acts as a support assistant for their Mini App using the context they give it. diff --git a/mini-apps/sharing/swap-qa.mdx b/mini-apps/sharing/swap-qa.mdx index 83a7b11..f180bad 100644 --- a/mini-apps/sharing/swap-qa.mdx +++ b/mini-apps/sharing/swap-qa.mdx @@ -93,5 +93,5 @@ console.log(link); ### Example link ``` -https://worldcoin.org/mini-app?app_id=app_6c5c5717c77abe83be8814c032c3a6f9&path=%2F%3FfromToken%3D0x2cFc85d8E48F8EAB294be644d9E25C3030863003 +https://worldcoin.org/mini-app?app_id=app_6c5c5717c77abe83be8814c032c3a6f9&path=%2F%3FfromToken%3D0x2cFc85d8E48F8EAB294be644d9E25C3030863003%26toToken%3D0x4200000000000000000000000000000000000006%26amount%3D1234500%26sourceAppId%3Dapp_source1234567890abcdef%26sourceAppName%3DMy%2520App ``` diff --git a/model-context-protocol/world-docs.mdx b/model-context-protocol/world-docs.mdx index d3c4817..4e3b4b7 100644 --- a/model-context-protocol/world-docs.mdx +++ b/model-context-protocol/world-docs.mdx @@ -28,7 +28,7 @@ The docs MCP does not require authentication. ```bash - codex mcp add world-docs -- npx -y mcp-remote https://docs.world.org/mcp --transport http-only + codex mcp add world-docs --url https://docs.world.org/mcp ```