Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added images/docs/world-id/idkit/invite-code-demo.mp4
Binary file not shown.
12 changes: 6 additions & 6 deletions world-id/idkit/javascript.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ if (!completion.success) {

## Invite-code mode

Use `IDKit.requestWithInviteCode(config)` to display a short code instead of a QR. Validation, the returned `Status` shape, and the poll loop are identical to `IDKit.request`. See [Invite-code mode](/world-id/idkit/verification-flows#with-invite-code-mode) for when to use it.
Use `IDKit.requestWithInviteCode(config)` to open a landing page that displays both an invite code and a QR code. Validation, the returned `Status` shape, and the poll loop are identical to `IDKit.request`. See [Invite-code mode](/world-id/idkit/verification-flows#with-invite-code-mode) for when to use it.

```ts
import { IDKit, selfieCheckLegacy } from "@worldcoin/idkit-core";
Expand All @@ -117,14 +117,14 @@ const request = await IDKit.requestWithInviteCode({
allow_legacy_proofs: true,
}).preset(selfieCheckLegacy({ signal: "user-123" }));

const code = request.code; // 6-character canonical form
const expiresAt = request.expiresAt; // Unix seconds
const connectorURI = request.connectorURI; // URL with &c=<code>&a=<app_id>
const expiresAt = request.expiresAt; // Unix seconds
const completion = await request.pollUntilCompletion();
```

`IDKitInviteCodeRequest` exposes:

- `code`
- `connectorURI`
- `expiresAt`
- `requestId`
- `pollOnce()`
Expand Down Expand Up @@ -154,12 +154,12 @@ const request = await IDKit.requestWithInviteCode({
allow_legacy_proofs: true,
}).preset(selfieCheckLegacy({ signal: "user-123" }));

const code = request.code; // display to user
const connectorURI = request.connectorURI; // display to user (URL with code embedded)
const expiresAt = request.expiresAt; // drive a countdown
const completion = await request.pollUntilCompletion();
```

The config object is unchanged. Replace `connectorURI` (QR) with `code` and `expiresAt` in your UI. Polling, proof verification, and nullifier storage stay the same.
The config object is unchanged. The `connectorURI` now includes `&c=<code>&a=<app_id>` params; use it alongside `expiresAt` in your UI. Polling, proof verification, and nullifier storage stay the same.

## Server-side helpers

Expand Down
2 changes: 1 addition & 1 deletion world-id/idkit/react.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ import { IDKitInviteCodeRequestWidget, selfieCheckLegacy } from "@worldcoin/idki
- `isAwaitingUserConfirmation`
- `isSuccess`
- `isError`
- `code`
- `connectorURI`
- `codeExpiresAt`
- `result`
- `errorCode`
Expand Down
12 changes: 6 additions & 6 deletions world-id/idkit/swift.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ Use `presetWithInviteCode(_:)` on the builder to return an `IDKitInviteCodeReque
let request = try IDKit.request(config: config)
.presetWithInviteCode(selfieCheckLegacy(signal: "user-123"))

let code = request.code // 6-character canonical form
let expiresAt = request.expiresAt // Date
let connectorURL = request.connectorURL // URL with &c=<code>&a=<app_id>
let expiresAt = request.expiresAt // Date
let completion = await request.pollUntilCompletion()
```

Expand All @@ -105,17 +105,17 @@ let completion = await request.pollUntilCompletion()
let request = try IDKit.request(config: config)
.presetWithInviteCode(selfieCheckLegacy(signal: "user-123"))

let code = request.code // display to user
let connectorURL = request.connectorURL // display to user (URL with code embedded)
let expiresAt = request.expiresAt // drive a countdown
let completion = await request.pollUntilCompletion()
```

The config object is unchanged. Replace `connectorURL` (QR) with `code` and `expiresAt` in your UI. Polling, proof verification, and nullifier storage stay the same.
The config object is unchanged. The `connectorURL` now includes `&c=<code>&a=<app_id>` params; use it alongside `expiresAt` in your UI. Polling, proof verification, and nullifier storage stay the same.

`IDKitInviteCodeRequest` exposes:

- `code: String`
- `connectorURL: URL`
- `expiresAt: Date`
- `requestID: UUID`
- `requestID: String`
- `pollStatusOnce() async -> IDKitStatus`
- `pollUntilCompletion(options:) async -> IDKitCompletionResult`
38 changes: 24 additions & 14 deletions world-id/idkit/verification-flows.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The cold flow requires the most steps and works differently on each platform bec

### Android

Android supports deferred deep linking through the Play Store. After the user downloads World App, the original verification context is carried forward at first launch — World App picks up where the user left off and routes them directly into credential enrollment. No re-trigger from your app is needed.
Android supports deferred deep linking through the Play Store. After the user downloads World App, the original verification context is carried forward at first launch — World App picks up where the user left off and routes them directly into credential enrollment.

```mermaid
sequenceDiagram
Expand Down Expand Up @@ -49,8 +49,6 @@ iOS does not support deferred deep linking through the App Store. The original v
3. World App opens and takes the user through a hot or warm flow.
4. The proof consent appears, the user approves, and the proof is returned to your app.

Because iOS does not preserve context through the App Store install, your app should direct the user to install World App before issuing the IDKit request.

```mermaid
sequenceDiagram
participant App as Your App
Expand Down Expand Up @@ -80,15 +78,25 @@ Invite-code mode displays a short 6-character code in your app that the user ent
</Note>

1. Your app triggers an IDKit invite-code request.
2. Your app opens the URL that IDKit provides. A landing page displays the invite code and a QR code for the request.
3. The user downloads World App from the App Store.
4. The user opens World App and completes account creation onboarding.
5. The user enters the invite code.
6. World App resolves the code, picks up the original verification context, and walks the user through credential enrollment.
7. The proof consent appears, the user approves, and the proof is returned to your app.
2. Your app opens the URL that IDKit provides. One of three paths follows:
- **User has World App (mobile):** World App launches directly via deep link.
- **User has World App (desktop):** The user scans the QR code with World App.
- **User needs to install World App:** The user installs World App, completes account onboarding, then enters the invite code to resume the request.
3. World App restores the verification context, walks the user through credential enrollment if needed, and presents a proof consent.
4. The user approves and the proof is returned to your app.

The 6-character code persists across the App Store install, so once World App is installed and onboarded the user can resume the verification flow without returning to your app first. This also covers cross-device scenarios (e.g., a desktop browser displaying the QR for the user's phone) where deep linking cannot carry context.

##### Demo

<div style={{ marginBottom: "32px" }}>
<video className="m-auto" width="700" autoPlay muted loop playsInline>
<source src="/images/docs/world-id/idkit/invite-code-demo.mp4" type="video/mp4" />
</video>
</div>

##### Flow diagram

```mermaid
sequenceDiagram
participant App as Your App
Expand All @@ -109,9 +117,11 @@ sequenceDiagram
WA-->>App: Proof returned
```

<div style={{ marginBottom: "32px" }} />

##### Lifecycle

- Codes expire after a short TTL (currently ten minutes).
- Codes expire after a short TTL (currently fifteen minutes).
- Codes are one-shot — once redeemed, they cannot be reused. Re-running the request returns a fresh code with a fresh TTL.
- After the user redeems the code, your existing poll loop receives the proof exactly as it does in QR mode.

Expand Down Expand Up @@ -139,8 +149,8 @@ const request = await IDKit.requestWithInviteCode({
environment: "production",
}).preset(selfieCheckLegacy({ signal: "user-123" }));

const code = request.code; // 6-character canonical form
const expiresAt = request.expiresAt; // Unix seconds
// Open the landing page — displays invite code + QR
window.open(request.connectorURI, "_blank");

const completion = await request.pollUntilCompletion();
```
Expand Down Expand Up @@ -205,8 +215,8 @@ let config = IDKitRequestConfig(
let request = try IDKit.request(config: config)
.presetWithInviteCode(selfieCheckLegacy(signal: "user-123"))

let code = request.code // 6-character canonical form
let expiresAt = request.expiresAt // Date
// Open the landing page — displays invite code + QR
await UIApplication.shared.open(request.connectorURL)

let completion = await request.pollUntilCompletion()
```
Expand Down
Loading