Setting Up SCP TypeScript Client
Overview
This guide shows how to set up the SCP TypeScript SDK client for the Service Commerce Platform API, authenticate using a Bearer token, and perform basic Tenant CRUD operations.
Getting Started
Prerequisites
- Node.js >= 18
- SCP API running locally on port 4000 (or use Docker Compose)
- Admin credentials for authentication
Quick Start with Docker
The SCP Docker image is hosted on GitHub Container Registry (GHCR). You'll need a Personal Access Token (PAT) with read:packages scope to pull the image.
Step 1: Authenticate with GHCR
Your PAT will be provided by your team lead via secure channel (email, 1Password, etc.).
# Login to GitHub Container Registry
# Replace YOUR_GITHUB_USERNAME and YOUR_PAT with actual values
echo "YOUR_PAT" | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin
Step 2: Download and Start
# Download docker-compose.yml from the documentation site
curl -O https://service-commerce-platform.alvera.ai/docker-compose.yml
# Download environment file
curl -O https://service-commerce-platform.alvera.ai/scp.env
# Start the platform
docker compose up -d
# API is now available at http://localhost:5001
Note: The Docker image pulls from
ghcr.io/alvera-ai/service-commerce-platform:0.4.0. Ensure you're authenticated before runningdocker compose up.
Installation
# Create a new project
mkdir my-scp-app && cd my-scp-app
npm init -y
# Install the SDK (generated from OpenAPI)
npm install @scp/sdk
# Or generate your own from the OpenAPI spec
npx openapi-typescript-codegen \
--input http://localhost:4000/api/openapi.yaml \
--output src/sdk \
--client fetch
API Flow
Code Examples
1. Authentication
import { OpenAPI, AuthenticationService } from '@scp/sdk';
// Configure base URL
OpenAPI.BASE = 'http://localhost:4000';
// Authenticate and get Bearer token
const auth = await AuthenticationService.sessionCreate({
requestBody: {
email: '[email protected]',
password: 'DevPassword123!',
tenant_name: 'alvera-scp-dev',
},
});
// Set token for all subsequent requests
OpenAPI.TOKEN = auth.token;
console.log('Authenticated successfully');
2. Create a Tenant
import { TenantService } from '@scp/sdk';
const tenant = await TenantService.tenantCreate({
requestBody: {
name: `My Salon ${Date.now()}`,
type: 'enterprise',
domain_name: 'my-salon.example.com',
},
});
console.log(`Created tenant: ${tenant.data.name} (${tenant.data.id})`);
3. Get Tenant by ID
const tenant = await TenantService.tenantShow({
id: tenantId,
});
console.log(`Retrieved tenant: ${tenant.data.name}`);
console.log(`Domain: ${tenant.data.domain_name}`);
4. List Tenants with Pagination
const result = await TenantService.tenantList({
page: 1,
pageSize: 10,
});
console.log(`Total tenants: ${result.meta.total_count}`);
console.log(`Page ${result.meta.page} of ${result.meta.total_pages}`);
for (const tenant of result.data) {
console.log(`- ${tenant.name} (${tenant.type})`);
}
5. Update Tenant
const updated = await TenantService.tenantUpdate({
id: tenantId,
requestBody: {
name: `Updated Salon ${Date.now()}`,
domain_name: 'updated.example.com',
},
});
console.log(`Updated tenant: ${updated.data.name}`);
6. Delete Tenant
await TenantService.tenantDelete({
id: tenantId,
});
console.log(`Deleted tenant: ${tenantId}`);
Using Client Samples
For convenience, you can use the pre-built client samples:
import { createTenant } from '@scp/client-samples/tenants/create';
import { listTenants } from '@scp/client-samples/tenants/list';
import { getTenant } from '@scp/client-samples/tenants/show';
import { updateTenant } from '@scp/client-samples/tenants/update';
import { deleteTenant } from '@scp/client-samples/tenants/delete';
// Create
const tenant = await createTenant();
// Read
const fetched = await getTenant(tenant.id);
// List
const { data, meta } = await listTenants();
// Update
const updated = await updateTenant(tenant.id);
// Delete
await deleteTenant(tenant.id);
Download: TypeScript Client Samples
Error Handling
try {
const tenant = await TenantService.tenantCreate({
requestBody: {
name: '', // Invalid - empty name
type: 'invalid_type', // Invalid enum
},
});
} catch (error) {
if (error.status === 422) {
console.error('Validation errors:', error.body.errors);
// { name: ["can't be blank"], type: ["is invalid"] }
}
}
API Response Format
Single Resource (GET, POST, PUT)
{
"data": {
"id": "80dbf797-6e35-4b5c-8cfb-703a79cce584",
"name": "My Salon",
"type": "enterprise",
"domain_name": "my-salon.example.com",
"inserted_at": "2024-01-15T10:30:00.123456Z",
"updated_at": "2024-01-15T10:30:00.123456Z"
}
}
List Response (GET with pagination)
{
"data": [
{ "id": "uuid1", "name": "Tenant 1", "..." : "..." },
{ "id": "uuid2", "name": "Tenant 2", "..." : "..." }
],
"meta": {
"page": 1,
"page_size": 10,
"total_count": 42,
"total_pages": 5
}
}
Error Response (422)
{
"errors": {
"name": ["can't be blank"],
"type": ["is invalid"]
}
}
Next Steps
After setting up the client, you can:
- Create merchant organizations under the tenant
- Set up service providers and services
- Configure appointment slots and availability
- Process bookings and payments
See the API Reference for all available endpoints.
Downloads
- Docker Compose - Run SCP locally
- OpenAPI Spec - Generate your own SDK
- Client Samples - Ready-to-use TypeScript examples
- Integration Tests - Vitest test suite