REST API
Friday Dev exposes a RESTful API for programmatic access.
Base URL
http://localhost:3000/api
For production:
https://your-domain.com/api
Authentication
API Key
Include your API key in the header:
Authorization: Bearer YOUR_API_KEY
Getting an API Key
friday-dev config get apiKey
# Or generate new:
friday-dev config set apiKey $(openssl rand -hex 32)
Tasks
List Tasks
GET /api/tasks
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status |
priority | string | Filter by priority |
project_id | string | Filter by project |
limit | number | Max results (default 50) |
offset | number | Skip results |
Response:
{
"tasks": [
{
"id": 123,
"title": "Add authentication",
"description": "Implement JWT auth",
"status": "in_progress",
"priority": "high",
"labels": ["backend", "security"],
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T14:20:00Z"
}
],
"total": 45,
"limit": 50,
"offset": 0
}
Get Task
GET /api/tasks/:id
Response:
{
"id": 123,
"title": "Add authentication",
"description": "Implement JWT auth",
"status": "in_progress",
"priority": "high",
"labels": ["backend", "security"],
"project_id": "proj_abc123",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T14:20:00Z",
"agent_runs": [
{
"id": "run_xyz",
"agent": "friday",
"status": "completed",
"started_at": "2024-01-15T11:00:00Z",
"completed_at": "2024-01-15T11:15:00Z"
}
]
}
Create Task
POST /api/tasks
Request Body:
{
"title": "Add login page",
"description": "Create a responsive login page",
"priority": "high",
"labels": ["frontend", "auth"],
"project_id": "proj_abc123"
}
Response:
{
"id": 124,
"title": "Add login page",
"description": "Create a responsive login page",
"status": "backlog",
"priority": "high",
"labels": ["frontend", "auth"],
"project_id": "proj_abc123",
"created_at": "2024-01-15T15:00:00Z"
}
Update Task
PATCH /api/tasks/:id
Request Body:
{
"status": "done",
"priority": "medium"
}
Delete Task
DELETE /api/tasks/:id
Response:
{
"success": true
}
Projects
List Projects
GET /api/projects
Response:
{
"projects": [
{
"id": "proj_abc123",
"name": "My App",
"path": "/path/to/project",
"created_at": "2024-01-01T00:00:00Z"
}
]
}
Get Project
GET /api/projects/:id
Create Project
POST /api/projects
Request Body:
{
"name": "New Project",
"path": "/path/to/project",
"git_url": "https://github.com/user/repo"
}
Delete Project
DELETE /api/projects/:id
Agent Runs
Run Agent
POST /api/tasks/:id/run
Request Body:
{
"agent": "friday",
"autonomy": "workspace-write",
"branch": "feature/auth"
}
Response:
{
"run_id": "run_xyz789",
"task_id": 123,
"agent": "friday",
"status": "running",
"started_at": "2024-01-15T16:00:00Z"
}
Get Run Status
GET /api/runs/:run_id
Response:
{
"id": "run_xyz789",
"task_id": 123,
"agent": "friday",
"status": "completed",
"started_at": "2024-01-15T16:00:00Z",
"completed_at": "2024-01-15T16:15:00Z",
"output": {
"files_modified": ["src/auth.ts", "src/routes.ts"],
"lines_added": 150,
"lines_removed": 20
}
}
Get Run Logs
GET /api/runs/:run_id/logs
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
since | timestamp | Logs after this time |
limit | number | Max log entries |
Response:
{
"logs": [
{
"timestamp": "2024-01-15T16:00:01Z",
"level": "info",
"message": "Reading task description..."
},
{
"timestamp": "2024-01-15T16:00:05Z",
"level": "info",
"message": "Analyzing codebase..."
}
]
}
Stop Run
POST /api/runs/:run_id/stop
Code Review
Review Task Output
POST /api/tasks/:id/review
Request Body:
{
"action": "approve"
}
Actions: approve, reject, request_changes
Review PR
POST /api/review/pr
Request Body:
{
"repo": "owner/repo",
"pr_number": 123,
"agent": "claude"
}
Labels
List Labels
GET /api/labels
Create Label
POST /api/labels
Request Body:
{
"name": "urgent",
"color": "#ff0000"
}
Error Responses
All errors follow this format:
{
"error": {
"code": "NOT_FOUND",
"message": "Task not found",
"details": {}
}
}
Error Codes
| Code | HTTP Status | Description |
|---|---|---|
BAD_REQUEST | 400 | Invalid request |
UNAUTHORIZED | 401 | Missing/invalid auth |
FORBIDDEN | 403 | Access denied |
NOT_FOUND | 404 | Resource not found |
CONFLICT | 409 | Resource conflict |
RATE_LIMITED | 429 | Too many requests |
INTERNAL_ERROR | 500 | Server error |
Rate Limiting
- Default: 100 requests/minute
- Authenticated: 1000 requests/minute
Headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1705334400
Pagination
List endpoints support pagination:
GET /api/tasks?limit=20&offset=40
Response includes:
{
"total": 100,
"limit": 20,
"offset": 40
}
Examples
cURL
# Create task
curl -X POST http://localhost:3000/api/tasks \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"title": "New task", "priority": "high"}'
# Run agent
curl -X POST http://localhost:3000/api/tasks/123/run \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"agent": "gemini"}'
JavaScript
const API_BASE = 'http://localhost:3000/api';
const API_KEY = 'YOUR_API_KEY';
async function createTask(title, priority) {
const response = await fetch(`${API_BASE}/tasks`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`
},
body: JSON.stringify({ title, priority })
});
return response.json();
}
Python
import requests
API_BASE = 'http://localhost:3000/api'
API_KEY = 'YOUR_API_KEY'
def create_task(title, priority):
response = requests.post(
f'{API_BASE}/tasks',
headers={'Authorization': f'Bearer {API_KEY}'},
json={'title': title, 'priority': priority}
)
return response.json()
Next Steps
- WebSockets - Real-time updates
- Authentication - Auth details
- CLI Reference - Command line alternative