ShopySeed

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 TypePurposeLifetimeLocation
Access TokenAPI authentication15 minutesAuthorization header
Refresh TokenToken renewal7 daysRequest 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: 1642248600

Authentication 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, required
  • password: Minimum 8 characters, must contain uppercase, lowercase, and number
  • name: 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

ParameterTypeDescription
tokenstringEmail 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

ParameterTypeDescription
idstringOrganization 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

ParameterTypeDescription
idstringOrganization 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

ParameterTypeDescription
idstringOrganization 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

ParameterTypeDescription
idstringOrganization 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

ParameterTypeDescription
idstringOrganization 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

ParameterTypeDescription
idstringOrganization UUID
userIdstringUser 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

ParameterTypeDescription
idstringOrganization UUID
userIdstringUser 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

HeaderValueDescription
X-Organization-IDstringOrganization 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

HeaderValueDescription
X-Organization-IDstringOrganization 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

HeaderValueDescription
X-Organization-IDstringOrganization 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

HeaderValueDescription
Stripe-SignaturestringStripe webhook signature
Content-Typeapplication/jsonRequired

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

CodeMeaningUsage
200OKSuccessful GET/PATCH requests
201CreatedSuccessful POST requests
204No ContentSuccessful DELETE requests
400Bad RequestValidation errors, malformed requests
401UnauthorizedInvalid or missing authentication
403ForbiddenInsufficient permissions
404Not FoundResource doesn't exist or access denied
409ConflictResource already exists or constraint violation
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnexpected server error
503Service UnavailableService 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.

On this page