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:
Authentication¶
All requests require an API key passed in the X-Api-Key header:
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:
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:
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-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.