
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
@startsimpli/api
Advanced tools
Type-safe Django REST API client for StartSimpli Next.js applications.
This package provides a type-safe TypeScript client for the Django REST API backend (start-simpli-api). It handles authentication, error normalization, pagination, and provides endpoint wrappers for all Django models.
IMPORTANT: This is a Django REST API client - NO Prisma, NO database code. All data lives in the Django backend.
npm install @startsimpli/api
import { createStartSimpliApi } from '@startsimpli/api';
const api = createStartSimpliApi({
baseUrl: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api/v1',
getToken: async () => {
// Get token from your auth provider
const session = await getServerSession();
return session?.accessToken || null;
},
});
// Use API endpoints
const contacts = await api.contacts.list({ tier: 1 });
const orgs = await api.organizations.getByStage('seed');
// List contacts with filters
const contacts = await api.contacts.list(
{ tier: 1, has_linkedin: true }, // filters
{ page: 1, page_size: 20 }, // pagination
{ ordering: '-created_at' } // sorting
);
// Get single contact
const contact = await api.contacts.get('contact-uuid');
// Create contact with assertions
const newContact = await api.contacts.create({
name: 'John Doe',
email: 'john@example.com',
title: 'Partner',
write_tags: ['tier_1', 'focus:fintech'],
write_metrics: { enrichment_score: 0.95 },
write_profiles: { linkedin: 'https://linkedin.com/in/johndoe' },
});
// Update contact
const updated = await api.contacts.update('contact-uuid', {
title: 'Managing Partner',
write_tags: ['tier_1', 'vip'],
});
// Search contacts
const results = await api.contacts.search('john');
// Get contacts by firm
const firmContacts = await api.contacts.getByFirm('firm-uuid');
// List organizations with filters
const orgs = await api.organizations.list(
{
tier: 1,
stage: 'seed',
check_size_min_gte: 100000,
check_size_max_lte: 1000000,
},
{ page: 1, page_size: 20 },
{ ordering: '-aum' }
);
// Get single organization
const org = await api.organizations.get('org-uuid');
// Create organization with assertions
const newOrg = await api.organizations.create({
name: 'Acme Ventures',
domain: 'acmevc.com',
location: 'San Francisco, CA',
write_tags: ['tier_1', 'stage:seed', 'focus:fintech'],
write_metrics: {
check_size_min: 500000,
check_size_max: 2000000,
aum: 100000000,
},
write_profiles: {
linkedin: 'https://linkedin.com/company/acme-ventures',
website: 'https://acmevc.com',
},
});
// Get by check size range
const firms = await api.organizations.getByCheckSizeRange(100000, 1000000);
// Tags
const tags = await api.entities.listTags();
// Entity Tags
const entityTags = await api.entities.listEntityTags(
{ page: 1, page_size: 50 },
{ entity_id: 'some-uuid', category: 'focus' }
);
// Metrics
const metrics = await api.entities.listMetrics(
undefined,
{ entity_id: 'some-uuid', type: 'financial' }
);
// Profiles
const profiles = await api.entities.listProfiles(
undefined,
{ entity_id: 'some-uuid', type: 'professional' }
);
For custom endpoints not covered by wrappers:
import { createApiClient } from '@startsimpli/api';
const client = createApiClient({
baseUrl: 'http://localhost:8000/api/v1',
getToken: async () => getAccessToken(),
});
// Direct fetch calls
const data = await client.fetch.get('/custom-endpoint/', {
params: { key: 'value' }
});
const created = await client.fetch.post('/custom-endpoint/', {
name: 'test'
});
import { withAuth } from '@startsimpli/api/middleware';
export const GET = withAuth(async (request, context) => {
const { userId, token, isAuthenticated } = context;
if (!isAuthenticated) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// Use token to call Django API
return NextResponse.json({ userId, token });
});
import { withValidation } from '@startsimpli/api/middleware';
import { z } from 'zod';
const createContactSchema = z.object({
name: z.string().min(1),
email: z.string().email().optional(),
tier: z.number().int().min(1).max(3).optional(),
});
export const POST = withValidation(
async (request, { body }) => {
// body is typed and validated
const contact = await createContact(body);
return NextResponse.json(contact);
},
{ body: createContactSchema }
);
import { withErrorHandling } from '@startsimpli/api/middleware';
export const GET = withErrorHandling(async (request) => {
// Errors are automatically caught and formatted
const data = await somethingThatMightThrow();
return NextResponse.json(data);
});
import { withAuth, withErrorHandling, withValidation } from '@startsimpli/api/middleware';
import { z } from 'zod';
const schema = z.object({ name: z.string() });
export const POST = withErrorHandling(
withAuth(
withValidation(
async (request, { body }, authContext) => {
// Fully typed, validated, and authenticated
return NextResponse.json({ success: true });
},
{ body: schema }
)
)
);
import {
isApiException,
isValidationError,
isAuthError,
isNotFoundError,
} from '@startsimpli/api';
try {
const contact = await api.contacts.get('invalid-id');
} catch (error) {
if (isValidationError(error)) {
console.log('Validation errors:', error.errors);
} else if (isAuthError(error)) {
console.log('Auth error:', error.status);
} else if (isNotFoundError(error)) {
console.log('Contact not found');
} else if (isApiException(error)) {
console.log('API error:', error.message);
}
}
All types are exported for use in your application:
import type {
Contact,
Organization,
Entity,
Tag,
Metric,
Profile,
Attribute,
PaginatedResponse,
ApiError,
CreateContactRequest,
UpdateContactRequest,
ContactFilters,
} from '@startsimpli/api';
This package is designed to work with the Django REST API:
http://localhost:8000/api/v1/ (configurable)@startsimpli/authpage, page_size)field__gte=100, field__in=1,2,3)Django uses a generic Entity model with assertions (Tags, Metrics, Profiles, Attributes):
// Entity with assertions
{
id: 'uuid',
entity_type: 'contact',
// Canonical fields
name: 'John Doe',
email: 'john@example.com',
// Computed from assertions
tier: 1, // from tags
linkedin: 'https://...', // from profiles
enrichment_score: 0.95, // from metrics
// Full assertions
tags: [{ category: 'quality', name: 'tier_1', ... }],
metrics: [{ type: 'quality', subtype: 'enrichment_score', value: 0.95 }],
profiles: [{ type: 'professional', subtype: 'linkedin', identifier: '...' }],
}
# Run tests
npm test
# Type check
npm run type-check
MIT
FAQs
Type-safe Django REST API client for StartSimpli apps
We found that @startsimpli/api demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.