Skip to content

API Overview

The FuncSpec REST API provides programmatic access to all platform features. Use it to integrate FuncSpec into your development workflow, CI/CD pipelines, or custom tooling.

Base URL

All API requests target:

https://funcspec.net/api/v1

Authentication

All requests require an API key passed in the X-Api-Key header:

curl https://funcspec.net/api/v1/projects \
  -H "X-Api-Key: your-api-key-here"

See API Authentication for key management details.

Request Format

  • All request bodies must be JSON with Content-Type: application/json
  • All responses are JSON
  • Date/time values use ISO 8601 format in UTC (e.g., 2026-03-15T14:32:11Z)

Response Format

Successful responses follow a consistent envelope:

{
  "data": { ... },
  "meta": { ... }
}

List responses include pagination metadata:

{
  "data": [
    { "id": 1, "title": "..." },
    { "id": 2, "title": "..." }
  ],
  "meta": {
    "total": 87,
    "page": 1,
    "per": 25
  }
}

Single-resource responses return the resource directly under data:

{
  "data": {
    "id": 42,
    "title": "User authentication",
    "type_of": "functional",
    "state": "accepted",
    "permalink": "F-1",
    "created_at": "2026-01-10T09:00:00Z",
    "updated_at": "2026-03-15T14:32:11Z"
  }
}

Pagination

List endpoints support cursor-based pagination via query parameters:

Parameter Default Description
page 1 Page number (1-indexed)
per 25 Items per page (max 100)

The response meta object always includes total — the count of all matching items regardless of pagination.

# Get the second page of 50 items
curl "https://funcspec.net/api/v1/projects/42/spec/items?page=2&per=50" \
  -H "X-Api-Key: $FUNCSPEC_API_KEY"

Error Handling

Errors return a non-2xx status code with a JSON body describing the problem:

{
  "error": {
    "code": "not_found",
    "message": "Project not found",
    "details": {}
  }
}

HTTP Status Codes

Code Meaning
200 OK Request succeeded
201 Created Resource created successfully
204 No Content Request succeeded, no response body (e.g., DELETE)
400 Bad Request Malformed request syntax
401 Unauthorized Missing or invalid API key
403 Forbidden Valid credentials, but insufficient permissions
404 Not Found Resource does not exist
422 Unprocessable Entity Validation errors on the submitted data
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Unexpected server error

Validation Errors (422)

When a request fails validation, the details field contains field-level errors:

{
  "error": {
    "code": "validation_failed",
    "message": "Validation failed",
    "details": {
      "title": ["can't be blank"],
      "type_of": ["must be 'functional' or 'technical'"]
    }
  }
}

Rate Limiting

All API keys are subject to rate limits. The current limit is included in every response header:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 987
X-RateLimit-Reset: 1743100800

X-RateLimit-Reset is a Unix timestamp indicating when the limit resets.

When you exceed the limit, you receive a 429 response:

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Try again after 2026-03-31T16:00:00Z"
  }
}

Limits by plan

Plan Requests/hour
Free 1,000
Pro 10,000
Enterprise Custom

Tip

Implement exponential backoff when you receive a 429. Start with a 1-second delay and double it on each subsequent retry, up to a maximum of 60 seconds.

Filtering and Sorting

Many list endpoints accept filter and sort query parameters documented per-endpoint. Common patterns:

# Filter by type
GET /projects/42/spec/items?type_of=functional

# Filter by tag
GET /projects/42/spec/items?tag=auth

# Full-text search
GET /projects/42/spec/items?q=password+reset

# Sort by creation date descending
GET /projects/42/spec/items?sort=-created_at

Sort parameters prefix field names with - for descending order.

Versioning

The current API version is v1. The version is part of the URL path. We will maintain backwards compatibility within a major version. When breaking changes are required, a new version will be introduced and the old version deprecated with adequate notice.

Next Steps