Initialize Client
Connect to the SCP API and authenticate. This is required before using other cookbook recipes.
Quick Links
- API Reference - Interactive API documentation with "Try it" functionality
- Setting Up SCP Client - Detailed SDK setup with Docker
- Overview - Platform architecture and capabilities
Interactive Demo
- Preview
- View Source
Connect
Login
Ready
InitializeClientDemo.jsx
import { useState, useEffect } from 'react';
import { OpenAPI, AuthenticationService, TenantService } from '@scp/sdk';
// Session storage for cookbook demos
const Session = {
save(data) {
const existing = this.load();
localStorage.setItem('scp_session', JSON.stringify({ ...existing, ...data }));
},
load() {
try {
return JSON.parse(localStorage.getItem('scp_session') || '{}');
} catch { return {}; }
},
clear() {
localStorage.removeItem('scp_session');
localStorage.removeItem('scp_token');
localStorage.removeItem('scp_api_url');
},
get tenantId() { return this.load().tenant_id; },
get isAuthenticated() {
return !!(this.load().tenant_id && OpenAPI.TOKEN);
},
};
export default function InitializeClientDemo() {
const [step, setStep] = useState(1);
const [apiUrl, setApiUrl] = useState('http://localhost:4000');
const [email, setEmail] = useState('[email protected]');
const [password, setPassword] = useState('DevPassword123!');
const [tenantName, setTenantName] = useState('alvera-scp-dev');
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [session, setSession] = useState(null);
// Check for existing session on mount
useEffect(() => {
const savedUrl = localStorage.getItem('scp_api_url');
const savedToken = localStorage.getItem('scp_token');
if (savedUrl) {
OpenAPI.BASE = savedUrl;
setApiUrl(savedUrl);
}
if (savedToken) {
OpenAPI.TOKEN = savedToken;
}
if (Session.isAuthenticated) {
setSession(Session.load());
setStep(3);
}
}, []);
const checkServer = async () => {
setLoading(true);
setError(null);
try {
OpenAPI.BASE = apiUrl;
localStorage.setItem('scp_api_url', apiUrl);
const res = await fetch(apiUrl + '/health-check');
if (!res.ok) throw new Error('Server not responding');
setStep(2);
} catch (err) {
setError('Cannot connect to ' + apiUrl);
} finally {
setLoading(false);
}
};
const login = async () => {
setLoading(true);
setError(null);
try {
// Use SDK AuthenticationService
const authResponse = await AuthenticationService.scpApiSessionControllerCreate({
requestBody: {
email,
password,
tenant_name: tenantName
}
});
// Store token
OpenAPI.TOKEN = authResponse.token;
localStorage.setItem('scp_token', authResponse.token);
// Get tenant ID using SDK
const tenantsResponse = await TenantService.tenantList({ page: 1, pageSize: 100 });
const tenants = tenantsResponse.data || tenantsResponse;
const tenant = tenants.find(t => t.name === tenantName);
if (!tenant) throw new Error('Tenant not found');
// Save session data
Session.save({
tenant_id: tenant.id,
tenant_name: tenantName,
email: email,
});
setSession({
tenant_id: tenant.id,
token: authResponse.token,
tenant_name: tenantName,
});
setStep(3);
} catch (err) {
setError('Login failed: ' + (err.body?.error || err.message));
} finally {
setLoading(false);
}
};
const resetSession = () => {
Session.clear();
OpenAPI.TOKEN = undefined;
setSession(null);
setStep(1);
};
const styles = {
container: {
padding: 24,
fontFamily: 'system-ui, -apple-system, sans-serif',
maxWidth: 480,
border: '1px solid #e5e7eb',
borderRadius: 12,
background: '#fff',
},
stepBar: {
display: 'flex',
gap: 8,
marginBottom: 20,
},
step: (active) => ({
flex: 1,
padding: 10,
background: active ? '#059669' : '#e5e7eb',
color: active ? 'white' : '#666',
borderRadius: 6,
textAlign: 'center',
fontSize: 12,
fontWeight: 500,
}),
input: {
width: '100%',
padding: 12,
borderRadius: 8,
border: '1px solid #d1d5db',
marginBottom: 12,
fontSize: 14,
boxSizing: 'border-box',
},
select: {
width: '100%',
padding: 12,
borderRadius: 8,
border: '1px solid #d1d5db',
marginBottom: 12,
fontSize: 14,
background: 'white',
boxSizing: 'border-box',
},
button: (bg) => ({
width: '100%',
padding: 14,
background: bg,
color: 'white',
border: 'none',
borderRadius: 8,
cursor: 'pointer',
marginTop: 8,
fontSize: 14,
fontWeight: 600,
}),
label: {
fontSize: 13,
fontWeight: 500,
color: '#374151',
marginBottom: 6,
display: 'block',
},
success: {
color: '#059669',
fontSize: 13,
marginBottom: 12,
display: 'flex',
alignItems: 'center',
gap: 6,
},
successBox: {
background: '#f0fdf4',
border: '1px solid #86efac',
borderRadius: 10,
padding: 20,
},
errorBox: {
marginTop: 12,
padding: 14,
background: '#fee2e2',
borderRadius: 8,
color: '#dc2626',
fontSize: 13,
},
codeBlock: {
background: '#1f2937',
color: '#10b981',
padding: 12,
borderRadius: 6,
fontSize: 12,
fontFamily: 'monospace',
marginTop: 12,
wordBreak: 'break-all',
},
link: {
display: 'inline-block',
marginTop: 16,
padding: '12px 20px',
background: '#059669',
color: 'white',
textDecoration: 'none',
borderRadius: 8,
fontSize: 14,
fontWeight: 500,
},
};
return (
<div style={styles.container}>
<div style={styles.stepBar}>
{[1, 2, 3].map(s => (
<div key={s} style={styles.step(step >= s)}>
{s === 1 ? 'Connect' : s === 2 ? 'Login' : 'Ready'}
</div>
))}
</div>
{step === 1 && (
<>
<label style={styles.label}>API Server</label>
<select value={apiUrl} onChange={e => setApiUrl(e.target.value)} style={styles.select}>
<option value="http://localhost:4000">Local Dev (port 4000)</option>
<option value="http://localhost:7000">Docker Mode (port 7000)</option>
<option value="https://iteration.service-commerce-platform.alvera.ai">Iteration Stack</option>
</select>
<button onClick={checkServer} disabled={loading} style={styles.button('#059669')}>
{loading ? 'Checking...' : 'Connect to Server'}
</button>
</>
)}
{step === 2 && (
<>
<p style={styles.success}>
<span>✓</span> Connected to {apiUrl}
</p>
<label style={styles.label}>Tenant Name</label>
<input value={tenantName} onChange={e => setTenantName(e.target.value)} style={styles.input} />
<label style={styles.label}>Email</label>
<input value={email} onChange={e => setEmail(e.target.value)} style={styles.input} />
<label style={styles.label}>Password</label>
<input type="password" value={password} onChange={e => setPassword(e.target.value)} style={styles.input} />
<button onClick={login} disabled={loading} style={styles.button('#059669')}>
{loading ? 'Authenticating...' : 'Sign In'}
</button>
</>
)}
{step === 3 && session && (
<div style={styles.successBox}>
<p style={{ fontWeight: 600, color: '#166534', margin: '0 0 16px 0', fontSize: 16 }}>
Client Initialized
</p>
<div style={{ fontSize: 13, color: '#15803d' }}>
<div style={{ marginBottom: 8 }}>
<strong>Tenant:</strong> {session.tenant_name}
</div>
<div style={{ marginBottom: 8 }}>
<strong>tenant_id:</strong> <code>{session.tenant_id?.substring(0, 12)}...</code>
</div>
</div>
<div style={styles.codeBlock}>
Bearer {OpenAPI.TOKEN?.substring(0, 40)}...
</div>
<p style={{ fontSize: 12, color: '#15803d', marginTop: 16, marginBottom: 0 }}>
Your bearer token is saved. Continue to Merchant Onboarding.
</p>
<a href="./merchant-onboarding" style={styles.link}>
Continue to Merchant Onboarding →
</a>
<button onClick={resetSession} style={{ ...styles.button('#dc2626'), marginTop: 12 }}>
Reset Session
</button>
</div>
)}
{error && <div style={styles.errorBox}>{error}</div>}
</div>
);
}
Development Environments
Choose your development environment:
| Environment | URL | Use Case |
|---|---|---|
| Local Docker | http://localhost:4000 or http://localhost:7000 | Local development with full control |
| Iteration Stack | https://iteration.service-commerce-platform.alvera.ai | Shared development environment on AWS Lightsail |
Code Reference
Install the SDK
# Generate SDK from OpenAPI spec
npx openapi-typescript-codegen \
--input http://localhost:4000/api/openapi \
--output ./generated \
--name ScpClient
# Or use the pre-built SDK package
npm install @scp/sdk
Authenticate
import { OpenAPI, AuthenticationService } from '@scp/sdk';
// Configure the base URL
OpenAPI.BASE = 'http://localhost:4000';
// Authenticate and get token
const authResponse = await AuthenticationService.scpApiSessionControllerCreate({
requestBody: {
email: '[email protected]',
password: 'DevPassword123!',
tenant_name: 'alvera-scp-dev',
},
});
// Set the token for all subsequent requests
OpenAPI.TOKEN = authResponse.token;
console.log('Authenticated as:', authResponse.user.email);
Next Steps
- Merchant Onboarding - Create merchant organization and location
- Service Manager - Manage service categories