Skip to content

API Reference Overview

!!! info "TL;DR" REST API at https://canviq.app/api. Authenticate with Bearer token. JSON request/response. Paginated results. Standard error format.

Base URL

All API endpoints are prefixed with:

https://canviq.app/api

For local development:

http://localhost:3000/api

Authentication

All authenticated endpoints require a Bearer token in the Authorization header:

curl https://canviq.app/api/submissions \
  -H "Authorization: Bearer your-api-key-here"

Get an API key from the admin dashboard under Settings → API Keys.

Public vs Authenticated Endpoints

Access Level Endpoints Example
Public Read submissions, categories, tags GET /api/submissions
Authenticated Vote, comment, create submissions POST /api/submissions/:id/vote
Admin Moderation, analytics, bulk actions POST /api/admin/merge
Agent MCP tools POST /api/mcp/tools

Content Type

All requests and responses use JSON:

Content-Type: application/json

Response Format

Success Response

{
  "data": {...},
  "meta": {
    "page": 1,
    "limit": 50,
    "total": 123
  }
}

Error Response

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid input",
    "details": [
      {
        "field": "title",
        "message": "Title must be at least 5 characters"
      }
    ]
  }
}

HTTP Status Codes

Code Meaning When
200 OK Successful GET, PATCH, DELETE
201 Created Successful POST
400 Bad Request Invalid input, validation failed
401 Unauthorized Missing or invalid API key
403 Forbidden Authenticated but lacking permissions
404 Not Found Resource doesn't exist
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Server error

Pagination

List endpoints return paginated results. Use query parameters to navigate:

GET /api/submissions?page=2&limit=25

Parameters:

  • page — Page number (1-indexed, default: 1)
  • limit — Items per page (default: 50, max: 100)

Response includes pagination metadata:

{
  "data": [...],
  "meta": {
    "page": 2,
    "limit": 25,
    "total": 123,
    "total_pages": 5,
    "has_next": true,
    "has_prev": true
  }
}

Filtering

Most list endpoints support filtering via query parameters:

GET /api/submissions?status=planned&category=feature-requests

Common filters:

  • status — Filter by submission status
  • category — Filter by category ID or slug
  • tag — Filter by tag slug
  • type — Filter by idea or problem
  • author — Filter by author ID
  • q — Full-text search query

Sorting

Use sort and order parameters:

GET /api/submissions?sort=votes&order=desc

Parameters:

  • sort — Field to sort by (created_at, votes, comments, title)
  • order — Sort direction (asc or desc, default: desc)

Rate Limits

Access Level Limit Window
Public 30 requests 1 minute
Authenticated 100 requests 1 minute
Admin 300 requests 1 minute
Agent Tier-based 1 minute

Rate limit headers are included in every response:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1675123456

If rate limited, the server returns 429 with:

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests",
    "retry_after": 42
  }
}

Field Expansion

Some endpoints support expanding related resources. Use the expand parameter:

GET /api/submissions/:id?expand=author,category,tags

Without expansion, you get IDs:

{
  "author_id": "uuid",
  "category_id": "uuid"
}

With expansion, you get full objects:

{
  "author": {
    "id": "uuid",
    "name": "Jane Doe",
    "avatar": "..."
  },
  "category": {
    "id": "uuid",
    "name": "Feature Requests",
    "slug": "feature-requests"
  }
}

Internationalization

Set the Accept-Language header to get localized content:

curl https://canviq.app/api/submissions \
  -H "Accept-Language: es"

Supported locales: en, es, fr, de, ru, pt-BR, ja, it

Category and tag names are returned in the requested locale if translations exist, otherwise fall back to English.

CORS

CORS is configured per-endpoint:

  • Read-only public endpoints (e.g., GET /api/submissions): Same-origin requests only. Cross-origin requests require the appropriate Access-Control-Allow-Origin header configured in the admin dashboard.
  • Authenticated endpoints: Require session cookies (sameSite: lax) which are only sent for same-site requests.
  • MCP endpoints: Accept Bearer token authentication (no cookie dependency).

!!! warning "CORS is NOT open by default" Unlike some APIs, Canviq does not enable Access-Control-Allow-Origin: *. Cross-origin access must be explicitly configured.

Webhooks

Subscribe to events via webhooks. Configure in admin dashboard under Settings → Webhooks.

Supported events:

  • submission.created
  • submission.updated
  • vote.created
  • comment.created
  • status.changed

What's Next