API Reference
Complete REST API documentation for ShopySeed with authentication, organization, and billing endpoints.
Complete REST API documentation for ShopySeed. All endpoints are available at http://localhost:3011 in development and your production API URL in production.
Base URL
- Development:
http://localhost:3011 - Production:
https://your-api-domain.com
Interactive Documentation
ShopySeed includes interactive Swagger documentation:
- Swagger UI:
{BASE_URL}/api - OpenAPI JSON:
{BASE_URL}/api-json
Authentication
Most endpoints require authentication via JWT Bearer token.
Authorization Header
Authorization: Bearer <access_token>Token Types
| Token Type | Purpose | Lifetime | Location |
|---|---|---|---|
| Access Token | API authentication | 15 minutes | Authorization header |
| Refresh Token | Token renewal | 7 days | Request body only |
Response Format
All API responses follow a consistent format:
Success Response
{
"data": {}, // Response data
"message": "Success", // Optional success message
"timestamp": "2024-01-15T10:30:00.000Z"
}Error Response
{
"statusCode": 400,
"message": "Validation failed",
"error": "Bad Request",
"timestamp": "2024-01-15T10:30:00.000Z",
"details": [] // Optional validation details
}Rate Limiting
All endpoints are rate-limited to prevent abuse:
- Limit: 10 requests per minute for auth endpoints, 100 requests per minute for other endpoints
- Headers: Rate limit info is returned in response headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1642248600Authentication Endpoints
Authentication and user management endpoints.
POST /auth/register
Register a new user account.
Auth Required: No
Rate Limit: 10 requests/minute
Request
{
"email": "user@example.com",
"password": "securePassword123",
"name": "John Doe" // Optional
}Validation Rules:
email: Valid email format, requiredpassword: Minimum 8 characters, must contain uppercase, lowercase, and numbername: Optional string
Response
Success (201)
{
"user": {
"id": "user-uuid",
"email": "user@example.com",
"name": "John Doe",
"emailVerified": false,
"createdAt": "2024-01-15T10:30:00.000Z"
},
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "refresh-token-uuid"
}Error (409)
{
"statusCode": 409,
"message": "User with this email already exists",
"error": "Conflict"
}Error (400)
{
"statusCode": 400,
"message": "Validation failed",
"error": "Bad Request",
"details": [
{
"field": "password",
"message": "Password must contain at least 8 characters, 1 uppercase letter and 1 number"
}
]
}POST /auth/login
Login with email and password.
Auth Required: No
Rate Limit: 10 requests/minute
Request
{
"email": "user@example.com",
"password": "securePassword123"
}Response
Success (200)
{
"user": {
"id": "user-uuid",
"email": "user@example.com",
"name": "John Doe",
"emailVerified": true,
"createdAt": "2024-01-15T10:30:00.000Z"
},
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "refresh-token-uuid"
}Error (401)
{
"statusCode": 401,
"message": "Invalid credentials",
"error": "Unauthorized"
}POST /auth/refresh
Refresh access token using refresh token.
Auth Required: No
Rate Limit: 10 requests/minute
Request
{
"refreshToken": "refresh-token-uuid"
}Response
Success (200)
{
"user": {
"id": "user-uuid",
"email": "user@example.com",
"name": "John Doe",
"emailVerified": true
},
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "new-refresh-token-uuid"
}Error (401)
{
"statusCode": 401,
"message": "Invalid or expired refresh token",
"error": "Unauthorized"
}POST /auth/logout
Logout and revoke refresh token.
Auth Required: Yes (Access Token)
Rate Limit: 10 requests/minute
Request
{
"refreshToken": "refresh-token-uuid"
}Response
Success (200)
{
"message": "Logged out successfully"
}GET /auth/verify-email/:token
Verify email address using verification token.
Auth Required: No
Rate Limit: 10 requests/minute
URL Parameters
| Parameter | Type | Description |
|---|---|---|
token | string | Email verification token from email |
Response
Success (200)
{
"message": "Email verified successfully"
}Error (404)
{
"statusCode": 404,
"message": "Invalid or expired verification token",
"error": "Not Found"
}GET /auth/me
Get current user profile.
Auth Required: Yes (Access Token)
Rate Limit: 100 requests/minute
Response
Success (200)
{
"id": "user-uuid",
"email": "user@example.com",
"name": "John Doe",
"avatarUrl": "https://example.com/avatar.jpg",
"emailVerified": true,
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}PATCH /auth/me
Update current user profile.
Auth Required: Yes (Access Token)
Rate Limit: 100 requests/minute
Request
{
"name": "John Smith", // Optional
"avatarUrl": "https://example.com/new-avatar.jpg" // Optional
}Response
Success (200)
{
"id": "user-uuid",
"email": "user@example.com",
"name": "John Smith",
"avatarUrl": "https://example.com/new-avatar.jpg",
"emailVerified": true,
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T11:00:00.000Z"
}Organization Endpoints
Multi-tenant organization management.
POST /organizations
Create a new organization. Creator becomes OWNER automatically.
Auth Required: Yes (Access Token)
Rate Limit: 100 requests/minute
Request
{
"name": "Acme Corporation",
"slug": "acme-corp", // Optional - auto-generated if not provided
"logoUrl": "https://example.com/logo.png" // Optional
}Response
Success (201)
{
"id": "org-uuid",
"name": "Acme Corporation",
"slug": "acme-corp",
"schemaName": "tenant_abc123",
"logoUrl": "https://example.com/logo.png",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}Error (409)
{
"statusCode": 409,
"message": "Organization slug 'acme-corp' already exists",
"error": "Conflict"
}GET /organizations
Get all organizations where the current user is a member.
Auth Required: Yes (Access Token)
Rate Limit: 100 requests/minute
Response
Success (200)
[
{
"id": "org-uuid",
"name": "Acme Corporation",
"slug": "acme-corp",
"schemaName": "tenant_abc123",
"logoUrl": "https://example.com/logo.png",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z",
"membership": {
"id": "member-uuid",
"role": "OWNER",
"joinedAt": "2024-01-15T10:30:00.000Z"
}
}
]GET /organizations/:id
Get organization details. User must be a member.
Auth Required: Yes (Access Token)
Rate Limit: 100 requests/minute
URL Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Organization UUID |
Response
Success (200)
{
"id": "org-uuid",
"name": "Acme Corporation",
"slug": "acme-corp",
"schemaName": "tenant_abc123",
"logoUrl": "https://example.com/logo.png",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z",
"membership": {
"id": "member-uuid",
"role": "MEMBER",
"joinedAt": "2024-01-15T10:30:00.000Z"
}
}Error (404)
{
"statusCode": 404,
"message": "Organization not found or access denied",
"error": "Not Found"
}PATCH /organizations/:id
Update organization details. Requires ADMIN or OWNER role.
Auth Required: Yes (Access Token + ADMIN+ role)
Rate Limit: 100 requests/minute
URL Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Organization UUID |
Request
{
"name": "Updated Corporation", // Optional
"slug": "updated-corp", // Optional
"logoUrl": "https://example.com/new-logo.png" // Optional
}Response
Success (200)
{
"id": "org-uuid",
"name": "Updated Corporation",
"slug": "updated-corp",
"schemaName": "tenant_abc123",
"logoUrl": "https://example.com/new-logo.png",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T11:00:00.000Z"
}Error (403)
{
"statusCode": 403,
"message": "Insufficient permissions",
"error": "Forbidden"
}DELETE /organizations/:id
Delete organization and drop tenant schema. Requires OWNER role.
Auth Required: Yes (Access Token + OWNER role)
Rate Limit: 100 requests/minute
URL Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Organization UUID |
Response
Success (204) No content returned.
Error (403)
{
"statusCode": 403,
"message": "Only organization owners can delete the organization",
"error": "Forbidden"
}GET /organizations/:id/members
Get all members of the organization.
Auth Required: Yes (Access Token + VIEWER+ role)
Rate Limit: 100 requests/minute
URL Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Organization UUID |
Response
Success (200)
[
{
"id": "member-uuid",
"role": "OWNER",
"joinedAt": "2024-01-15T10:30:00.000Z",
"user": {
"id": "user-uuid",
"email": "owner@example.com",
"name": "John Doe",
"avatarUrl": "https://example.com/avatar.jpg"
}
},
{
"id": "member-uuid-2",
"role": "MEMBER",
"joinedAt": "2024-01-16T09:00:00.000Z",
"user": {
"id": "user-uuid-2",
"email": "member@example.com",
"name": "Jane Smith",
"avatarUrl": null
}
}
]POST /organizations/:id/members
Invite a user to the organization by email. Requires ADMIN or OWNER role.
Auth Required: Yes (Access Token + ADMIN+ role)
Rate Limit: 100 requests/minute
URL Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Organization UUID |
Request
{
"email": "newmember@example.com",
"role": "MEMBER" // VIEWER | MEMBER | ADMIN | OWNER
}Response
Success (201)
{
"id": "member-uuid",
"role": "MEMBER",
"joinedAt": "2024-01-15T11:00:00.000Z",
"user": {
"id": "user-uuid",
"email": "newmember@example.com",
"name": "New Member",
"avatarUrl": null
}
}Error (404)
{
"statusCode": 404,
"message": "User with email 'newmember@example.com' not found",
"error": "Not Found"
}Error (409)
{
"statusCode": 409,
"message": "User is already a member of this organization",
"error": "Conflict"
}PATCH /organizations/:id/members/:userId
Update member role. Requires ADMIN or OWNER role. OWNER role changes require OWNER.
Auth Required: Yes (Access Token + ADMIN+ role)
Rate Limit: 100 requests/minute
URL Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Organization UUID |
userId | string | User UUID |
Request
{
"role": "ADMIN" // VIEWER | MEMBER | ADMIN | OWNER
}Response
Success (200)
{
"id": "member-uuid",
"role": "ADMIN",
"joinedAt": "2024-01-15T10:30:00.000Z",
"user": {
"id": "user-uuid",
"email": "user@example.com",
"name": "John Doe",
"avatarUrl": "https://example.com/avatar.jpg"
}
}DELETE /organizations/:id/members/:userId
Remove member from organization. Requires ADMIN or OWNER role. Cannot remove last OWNER.
Auth Required: Yes (Access Token + ADMIN+ role)
Rate Limit: 100 requests/minute
URL Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Organization UUID |
userId | string | User UUID |
Response
Success (204) No content returned.
Error (403)
{
"statusCode": 403,
"message": "Cannot remove the last owner from the organization",
"error": "Forbidden"
}Billing Endpoints
Stripe billing and subscription management.
GET /billing/plans
Get available subscription plans.
Auth Required: No
Rate Limit: 100 requests/minute
Response
Success (200)
{
"free": {
"name": "Free",
"stripePriceId": null,
"price": null,
"limits": {
"members": 3,
"storage": "1GB"
},
"features": [
"Up to 3 team members",
"1GB storage",
"Basic support"
]
},
"starter": {
"name": "Starter",
"stripePriceId": "price_1234567890",
"price": 29,
"limits": {
"members": 10,
"storage": "10GB"
},
"features": [
"Up to 10 team members",
"10GB storage",
"Email support",
"Advanced features"
]
},
"pro": {
"name": "Pro",
"stripePriceId": "price_0987654321",
"price": 99,
"limits": {
"members": 50,
"storage": "100GB"
},
"features": [
"Up to 50 team members",
"100GB storage",
"Priority support",
"Advanced features",
"API access"
]
}
}GET /billing/subscription
Get current subscription details for the organization.
Auth Required: Yes (Access Token + Organization Context)
Rate Limit: 100 requests/minute
Headers
| Header | Value | Description |
|---|---|---|
X-Organization-ID | string | Organization UUID |
Response
Success (200)
{
"id": "subscription-uuid",
"plan": "starter",
"status": "active",
"currentPeriodStart": "2024-01-15T00:00:00.000Z",
"currentPeriodEnd": "2024-02-15T00:00:00.000Z",
"cancelAtPeriodEnd": false,
"stripeCustomerId": "cus_1234567890",
"stripeSubscriptionId": "sub_1234567890"
}POST /billing/checkout
Create Stripe checkout session for plan upgrade.
Auth Required: Yes (Access Token + Organization Context + ADMIN+ role)
Rate Limit: 100 requests/minute
Headers
| Header | Value | Description |
|---|---|---|
X-Organization-ID | string | Organization UUID |
Request
{
"planKey": "starter" // Plan key from /billing/plans
}Response
Success (201)
{
"sessionId": "cs_1234567890",
"url": "https://checkout.stripe.com/pay/cs_1234567890#fidkdWxOYH..."
}Error (400)
{
"statusCode": 400,
"message": "Organization already has an active subscription",
"error": "Bad Request"
}POST /billing/portal
Create Stripe billing portal session for subscription management.
Auth Required: Yes (Access Token + Organization Context + ADMIN+ role)
Rate Limit: 100 requests/minute
Headers
| Header | Value | Description |
|---|---|---|
X-Organization-ID | string | Organization UUID |
Response
Success (201)
{
"url": "https://billing.stripe.com/session/1234567890"
}Error (400)
{
"statusCode": 400,
"message": "No billing information found for this organization",
"error": "Bad Request"
}POST /billing/webhooks
Stripe webhook handler for subscription events.
Auth Required: No (Webhook signature verification)
Rate Limit: No limit
Headers
| Header | Value | Description |
|---|---|---|
Stripe-Signature | string | Stripe webhook signature |
Content-Type | application/json | Required |
Request
Raw Stripe webhook payload (handled automatically by Stripe).
Response
Success (200)
{
"received": true
}Error (400)
{
"statusCode": 400,
"message": "Invalid webhook signature",
"error": "Bad Request"
}Health Endpoints
Service health monitoring endpoints.
GET /health
Basic health check for the application.
Auth Required: No
Rate Limit: No limit
Response
Success (200)
{
"status": "ok",
"timestamp": "2024-01-15T10:30:00.000Z",
"uptime": 3600,
"version": "1.0.0"
}GET /health/ready
Readiness check with database and Redis connectivity.
Auth Required: No
Rate Limit: No limit
Response
Success (200)
{
"status": "ok",
"timestamp": "2024-01-15T10:30:00.000Z",
"checks": {
"database": {
"status": "ok",
"responseTime": 12
},
"redis": {
"status": "ok",
"responseTime": 3
}
}
}Error (503)
{
"status": "error",
"timestamp": "2024-01-15T10:30:00.000Z",
"checks": {
"database": {
"status": "error",
"error": "Connection timeout"
},
"redis": {
"status": "ok",
"responseTime": 3
}
}
}Error Codes Reference
HTTP Status Codes
| Code | Meaning | Usage |
|---|---|---|
200 | OK | Successful GET/PATCH requests |
201 | Created | Successful POST requests |
204 | No Content | Successful DELETE requests |
400 | Bad Request | Validation errors, malformed requests |
401 | Unauthorized | Invalid or missing authentication |
403 | Forbidden | Insufficient permissions |
404 | Not Found | Resource doesn't exist or access denied |
409 | Conflict | Resource already exists or constraint violation |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Unexpected server error |
503 | Service Unavailable | Service temporarily unavailable |
Common Error Messages
Authentication Errors
"Invalid or expired access token""Invalid or expired refresh token""Email not verified""Invalid credentials"
Authorization Errors
"Insufficient permissions""Organization not found or access denied""Only organization owners can perform this action"
Validation Errors
"Validation failed"(with details array)"Email address is required""Password must meet security requirements""Organization slug already exists"
Rate Limiting
"Too many requests, please try again later"
SDK and Client Libraries
JavaScript/TypeScript Client
ShopySeed includes a type-safe API client generated from the OpenAPI specification:
import { ShopySeedClient } from '@shopyseed/client';
const client = new ShopySeedClient({
baseURL: 'https://api.shopyseed.com',
apiKey: 'your-api-key'
});
// Type-safe API calls
const user = await client.auth.getMe();
const organizations = await client.organizations.list();Example Usage
Authentication Flow
// Register new user
const { user, accessToken, refreshToken } = await client.auth.register({
email: 'user@example.com',
password: 'securePassword123',
name: 'John Doe'
});
// Store tokens securely
localStorage.setItem('accessToken', accessToken);
localStorage.setItem('refreshToken', refreshToken);
// Set client authentication
client.setAuth(accessToken);Organization Management
// Create organization
const organization = await client.organizations.create({
name: 'My Company',
slug: 'my-company'
});
// Invite member
await client.organizations.inviteMember(organization.id, {
email: 'member@example.com',
role: 'MEMBER'
});
// List members
const members = await client.organizations.getMembers(organization.id);Billing Integration
// Get available plans
const plans = await client.billing.getPlans();
// Create checkout session
const { url } = await client.billing.createCheckoutSession({
planKey: 'starter'
});
// Redirect to Stripe Checkout
window.location.href = url;This API provides a complete foundation for building SaaS applications with authentication, multi-tenancy, and billing capabilities.