Examples
API reference
A long, field-heavy reference page for a fictional HTTP API.
This reference documents a fictional project management API. It exists to show how dense reference material reads: many sections, many fields, and code in several languages.
Overview
All requests go to https://api.example.com/v1. Requests and responses use JSON. Timestamps are ISO 8601 strings in UTC.
v1 is the current version. Breaking changes ship under a new version prefix.
Authentication
Authenticate with a bearer token in the Authorization header. Create tokens in your account settings.
curl https://api.example.com/v1/projects \
-H "Authorization: Bearer $TOKEN"const response = await fetch('https://api.example.com/v1/projects', {
headers: { Authorization: `Bearer ${token}` },
});import requests
response = requests.get(
"https://api.example.com/v1/projects",
headers={"Authorization": f"Bearer {token}"},
)Errors
Errors return a non-2xx status and a JSON body with a machine-readable code.
{
"error": {
"code": "project_not_found",
"message": "No project with id prj_123 exists."
}
}| Status | Meaning |
|---|---|
400 |
The request body or query is invalid |
401 |
The token is missing or expired |
403 |
The token lacks permission for this resource |
404 |
The resource does not exist |
429 |
Too many requests, see rate limits |
Pagination
List endpoints return at most limit items and a next cursor. Pass the cursor to get the next page.
limitintegerdefault: 20
cursorstring
next value from the previous response.Rate limits
Each token may make 600 requests per minute. Responses include the remaining budget.
X-RateLimit-Limitheader
X-RateLimit-Remainingheader
X-RateLimit-Resetheader
Projects
A project groups tasks and members.
The project object
idstring
prj_.namestring
descriptionstring | null
status'active' | 'archived'
created_atstring
List projects
GET /projects
curl https://api.example.com/v1/projects?limit=2 \
-H "Authorization: Bearer $TOKEN"{
"data": [
{ "id": "prj_1", "name": "Website", "status": "active" },
{ "id": "prj_2", "name": "Mobile app", "status": "active" }
],
"next": "cur_9f2"
}Create a project
POST /projects
namestringrequired
descriptionstring
curl https://api.example.com/v1/projects \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "name": "Docs" }'Archive a project
POST /projects/:id/archive
Archiving is reversible. Archived projects keep their tasks but reject writes.
Tasks
A task belongs to exactly one project.
The task object
idstring
tsk_.project_idstring
titlestring
assignee_idstring | null
due_atstring | null
state'todo' | 'doing' | 'done'default: 'todo'
List tasks
GET /projects/:id/tasks
state'todo' | 'doing' | 'done'
assignee_idstring
Update a task
PATCH /tasks/:id
Send only the fields you want to change.
await fetch(`https://api.example.com/v1/tasks/${id}`, {
method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ state: 'done' }),
});Delete a task
DELETE /tasks/:id
Deletion is permanent.
Members
Members are people with access to a project.
The member object
idstring
mem_.emailstring
role'owner' | 'editor' | 'viewer'
Invite a member
POST /projects/:id/members
emailstringrequired
role'editor' | 'viewer'default: 'viewer'
Webhooks
Webhooks send a POST request to your URL when something changes.
Events
| Event | Sent when |
|---|---|
project.created |
A project is created |
project.archived |
A project is archived |
task.created |
A task is created |
task.updated |
Any task field changes |
member.invited |
A member is invited |
Verifying signatures
Every delivery includes an X-Signature header: an HMAC-SHA256 of the raw body with your webhook secret.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifySignature(body: string, signature: string, secret: string) {
const expected = createHmac('sha256', secret).update(body).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signature);
return a.length === b.length && timingSafeEqual(a, b);
}
export async function handleWebhook(request: Request, secret: string) {
const body = await request.text();
const signature = request.headers.get('X-Signature') ?? '';
if (!verifySignature(body, signature, secret)) {
return new Response('Invalid signature', { status: 401 });
}
const event = JSON.parse(body);
console.log(`Received ${event.type}`);
return new Response(null, { status: 204 });
}Retries
Failed deliveries are retried with exponential backoff for up to 24 hours. Respond with any 2xx status to acknowledge.
Changelog
2026-09-01
- Added
due_atto tasks. limitnow accepts up to 100.
2026-06-15
- Added webhooks.
- Deprecated the
ownerquery parameter on/projects. Deprecated
2026-03-02
- Initial release.