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.services.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.services.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