Skip to main content

Project Routes

Public and user-facing endpoints for projects.

GET /api/projects

List projects with filters and pagination.

Query params:

ParamTypeDefaultNotes
statusstringlivelive / pending / rejected
categorystringCategory slug. Filters by slug membership.
spherestringSphere name. Same idea.
pricingstringallall / free / freemium / paid
sortstringnewestAny key from directoryConfig.sortOptions
pagenumber1Page number
limitnumber40Items per page
qstringSearch query (substring match)

Response:

{
  "data": [ /* array of projects */ ],
  "meta": {
    "total": 1248,
    "page": 1,
    "pageSize": 40,
    "hasMore": true
  }
}

GET /api/projects/[slug]

Get a single project. Returns 404 if not live (unless the request is from the owner or an admin).

POST /api/projects

Create a new submission. Requires auth.

Submission form preview:

/submit project submission form

Body: validated by ProjectSubmissionSchema from lib/validations/schemas.ts:

{
  plan: 'standard' | 'premium',
  name: string,
  slug: string,              // auto-generated if empty
  url: string,
  description: string,
  long_description?: string,
  categories: string[],      // array of category slugs
  logo_url?: string,
  screenshots?: string[],
  pricing_type: 'free' | 'freemium' | 'paid',
  // ... more fields
}

Response:

  • If plan is premium, returns a Stripe Checkout URL — redirect user there
  • If plan is standard, returns the created project ID directly

Rate-limited: submission tier.

PUT /api/projects/[id]

Update an existing project. Requires ownership or admin.

Body mirrors POST — partial updates supported. Status transitions (pending → live) are admin-only.

DELETE /api/projects/[id]

Delete a project. Requires ownership or admin. Soft-delete by default (sets deleted_at); admins can hard-delete via /api/admin/projects/[id].

POST /api/projects/[id]/upvote

Toggle upvote. Body: none. Requires auth.

Rate-limited: voting tier.

Response:

{ "data": { "upvoted": true, "upvote_count": 42 } }

GET /api/projects/[id]/comments

List comments on a project. Paginated.

Feature-flagged: returns 404 if comments: false in features.config.ts.

POST /api/projects/[id]/comments

Add a comment. Requires auth. Rate-limited.

POST /api/projects/[id]/ratings

Add or update this user's rating. Requires auth.

Body: { "rating": 1..5 }.

Error examples

// Missing auth
{ "error": "Unauthorized" }                  // 401
 
// Tried to edit someone else's project
{ "error": "Forbidden" }                     // 403
 
// Feature disabled
{ "error": "Not found" }                     // 404
 
// Validation failed
{
  "error": "Invalid input",
  "details": { "name": { "_errors": ["Required"] } }
}                                            // 400
 
// Rate limited
{
  "error": "Too many requests",
  "retryAfter": 60
}                                            // 429