Quickstart
Get up and running with the Web / React SDK in 5 minutes.
Prerequisites
- React 16.8+ (hooks support)
- A Passage Connect API key
Step 1: Install
npm install @getpassage/web-reactStep 2: Add PassageProvider
Wrap your app (or the relevant subtree) with PassageProvider. This renders the App Clip modal and manages WebSocket connections.
import { PassageProvider } from "@getpassage/web-react";
function App() {
return (
<PassageProvider>
<MyComponent />
</PassageProvider>
);
}Step 3: Create a link on your backend
Your backend creates a link via the Connect API and returns the claimCode to the frontend.
curl -X POST https://connect.getpassage.ai/v1/links \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"integrationId": "tmobile",
"resource": "mobileBillingStatement",
"action": "read",
"webhookUrl": "https://your-server.com/webhook"
}'The response includes a claimCode (e.g. clm_xxx). Return this to your frontend.
// Example Node.js backend route
app.post("/api/create-link", async (req, res) => {
const response = await fetch("https://connect.getpassage.ai/v1/links", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PASSAGE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
integrationId: "tmobile",
resource: "mobileBillingStatement",
action: "read",
webhookUrl: "https://your-server.com/webhook",
}),
});
const link = await response.json();
res.json({ claimCode: link.claimCode });
});Step 4: Open the App Clip
Use the usePassage hook to call openAppClip with the claim code. The SDK shows a QR code modal and monitors the link status via WebSocket.
import { usePassage } from "@getpassage/web-react";
function MyComponent() {
const { openAppClip } = usePassage();
const handleConnect = async () => {
const res = await fetch("/api/create-link", { method: "POST" });
const { claimCode } = await res.json();
openAppClip({
claimCode,
onConnectionComplete: () => {
console.log("Account connected!");
},
onConnectionError: (error) => {
console.error("Connection failed:", error.error);
},
});
};
return <button onClick={handleConnect}>Connect Account</button>;
}Full example
import React, { useState } from "react";
import { PassageProvider, usePassage } from "@getpassage/web-react";
import type { PassageErrorData } from "@getpassage/web-react";
function App() {
return (
<PassageProvider>
<ConnectAccount />
</PassageProvider>
);
}
function ConnectAccount() {
const { openAppClip } = usePassage();
const [status, setStatus] = useState("");
const [isLoading, setIsLoading] = useState(false);
const connectAccount = async () => {
setIsLoading(true);
setStatus("");
try {
const res = await fetch("/api/create-link", { method: "POST" });
const { claimCode } = await res.json();
openAppClip({
claimCode,
onConnectionComplete: () => {
setStatus("Connected successfully!");
setIsLoading(false);
},
onConnectionError: (error: PassageErrorData) => {
setStatus(`Failed: ${error.error}`);
setIsLoading(false);
},
});
} catch (error) {
setStatus(`Error: ${error instanceof Error ? error.message : "Unknown"}`);
setIsLoading(false);
}
};
return (
<div>
<button onClick={connectAccount} disabled={isLoading}>
{isLoading ? "Connecting..." : "Connect Account"}
</button>
{status && <p>{status}</p>}
</div>
);
}
export default App;Next steps
- API Reference — Full type and function docs
- Create Link API — Link creation endpoint details
- Webhook Verification — Verify webhook signatures
- Migration Guide — Migrating from the legacy
@getpassage/react-jsSDK
Last updated on