Taskboards API & Webhooks
Learn about Taskboards API & Webhooks in WaymakerOS.
Taskboards API & Webhooks
Waymaker provides a comprehensive REST API and webhook system for integrating taskboards with external tools, building custom automation, and creating powerful workflows.
API Overview
Base URL
https://api.waymakerone.com/v1
Authentication
All API requests require authentication using an API key.
Obtaining an API Key:
- Navigate to Settings → API Keys
- Click "Generate New API Key"
- Name your key (e.g., "CI/CD Integration")
- Copy the key (shown only once)
- Store securely (treat like a password)
Authentication Header:
Authorization: Bearer <YOUR_API_KEY>
Example Request:
curl -X GET \
https://api.waymakerone.com/v1/boards \
-H 'Authorization: Bearer <YOUR_API_KEY>'
API Key Types
Organization Keys (Recommended):
- Scoped to entire organization
- Can access all organization boards
- Managed by organization admins
- Ideal for integrations and automation
Personal Keys:
- Scoped to individual user
- Inherits user's permissions
- Managed in personal settings
- Ideal for personal scripts and tools
Service Keys (Enterprise):
- Machine-to-machine authentication
- No user context
- Highest rate limits
- Managed by organization owners
Rate Limits
Standard Tier:
- 1,000 requests per hour
- 100 requests per minute
- Burst allowance: 200 requests
Pro Tier:
- 5,000 requests per hour
- 500 requests per minute
- Burst allowance: 1,000 requests
Enterprise Tier:
- 20,000 requests per hour
- 2,000 requests per minute
- Custom burst allowance
Rate Limit Headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 987
X-RateLimit-Reset: 1704067200
X-RateLimit-Retry-After: 3600
Handling Rate Limits:
async function makeApiRequest(url: string) {
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
},
});
if (response.status === 429) {
const retryAfter = response.headers.get('X-RateLimit-Retry-After');
console.log(`Rate limited. Retry after ${retryAfter} seconds`);
await sleep(parseInt(retryAfter) * 1000);
return makeApiRequest(url); // Retry
}
return response.json();
}
API Endpoints
Boards
List Boards
GET /v1/boards
Query Parameters:
organization_id(required): Organization UUIDarchived(optional): Include archived boards (default: false)limit(optional): Results per page (max: 100, default: 50)offset(optional): Pagination offset
Response:
{
"data": [
{
"id": "board-uuid-123",
"organization_id": "org-uuid-456",
"name": "Q1 Product Launch",
"description": "Launch planning for new product",
"created_by": "user-uuid-789",
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-10T12:34:56Z",
"archived": false,
"settings": {
"workflow": {
"default_sections": ["To Do", "In Progress", "Done"]
}
}
}
],
"pagination": {
"total": 15,
"limit": 50,
"offset": 0,
"has_more": false
}
}
Get Board
GET /v1/boards/{board_id}
Response:
{
"id": "board-uuid-123",
"organization_id": "org-uuid-456",
"name": "Q1 Product Launch",
"description": "Launch planning for new product",
"created_by": "user-uuid-789",
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-10T12:34:56Z",
"archived": false,
"settings": {
"workflow": {
"default_sections": ["To Do", "In Progress", "Done"]
}
},
"members": [
{
"user_id": "user-uuid-789",
"role": "owner",
"added_at": "2025-01-01T00:00:00Z"
}
],
"statistics": {
"total_tasks": 45,
"completed_tasks": 23,
"active_layers": 3
}
}
Create Board
POST /v1/boards
Request Body:
{
"organization_id": "org-uuid-456",
"name": "Q2 Marketing Campaign",
"description": "Marketing initiatives for Q2",
"settings": {
"workflow": {
"default_sections": ["Backlog", "In Progress", "Review", "Done"]
}
}
}
Response: Same as Get Board
Update Board
PATCH /v1/boards/{board_id}
Request Body (partial updates allowed):
{
"name": "Q2 Marketing Campaign - Updated",
"description": "Updated description",
"settings": {
"workflow": {
"default_sections": ["To Do", "Doing", "Done"]
}
}
}
Delete Board
DELETE /v1/boards/{board_id}
Response:
{
"deleted": true,
"id": "board-uuid-123"
}
Tasks
List Tasks
GET /v1/boards/{board_id}/tasks
Query Parameters:
section(optional): Filter by section (e.g., "To Do")layer_id(optional): Filter by layerassignee_id(optional): Filter by assigneestatus(optional): Filter by statuspriority(optional): Filter by prioritytags(optional): Filter by tags (comma-separated)due_before(optional): Due date before (ISO 8601)due_after(optional): Due date after (ISO 8601)limit(optional): Results per page (max: 100)offset(optional): Pagination offsetsort(optional): Sort field (default: sort_order)order(optional): Sort direction (asc/desc, default: asc)
Response:
{
"data": [
{
"id": "task-uuid-123",
"board_id": "board-uuid-456",
"layer_id": "layer-uuid-789",
"section": "In Progress",
"title": "Design user dashboard",
"description": "Create mockups for the new user dashboard",
"assignee_id": "user-uuid-abc",
"reporter_id": "user-uuid-def",
"priority": "high",
"status": "In Progress",
"task_number": 42,
"sort_order": 1024.5,
"due_date": "2025-01-15",
"completed_at": null,
"estimated_hours": 8.0,
"actual_hours": 5.5,
"tags": ["design", "ui", "priority"],
"metadata": {
"custom_fields": {
"customer": "Acme Corp"
}
},
"created_at": "2025-01-08T10:00:00Z",
"updated_at": "2025-01-10T15:30:00Z"
}
],
"pagination": {
"total": 45,
"limit": 50,
"offset": 0,
"has_more": false
}
}
Get Task
GET /v1/tasks/{task_id}
Query Parameters:
include(optional): Comma-separated list of related data to includecomments: Include task commentsattachments: Include task attachmentsdependencies: Include task dependenciesall: Include everything
Response:
{
"id": "task-uuid-123",
"board_id": "board-uuid-456",
"layer_id": "layer-uuid-789",
"section": "In Progress",
"title": "Design user dashboard",
"description": "Create mockups for the new user dashboard",
"assignee": {
"id": "user-uuid-abc",
"name": "Sarah Johnson",
"email": "sarah@example.com",
"avatar_url": "https://..."
},
"reporter": {
"id": "user-uuid-def",
"name": "Mike Chen",
"email": "mike@example.com",
"avatar_url": "https://..."
},
"priority": "high",
"status": "In Progress",
"task_number": 42,
"sort_order": 1024.5,
"due_date": "2025-01-15",
"completed_at": null,
"estimated_hours": 8.0,
"actual_hours": 5.5,
"tags": ["design", "ui", "priority"],
"metadata": {
"custom_fields": {
"customer": "Acme Corp"
},
"checklist": [
{
"id": "check1",
"text": "Create wireframes",
"completed": true
},
{
"id": "check2",
"text": "High-fidelity mockups",
"completed": false
}
]
},
"comments": [
{
"id": "comment-uuid-123",
"user_id": "user-uuid-abc",
"content": "Initial wireframes complete",
"created_at": "2025-01-09T14:20:00Z"
}
],
"attachments": [
{
"id": "attachment-uuid-456",
"file_name": "dashboard-wireframe.png",
"file_size": 245632,
"mime_type": "image/png",
"url": "https://storage.waymakerone.com/..."
}
],
"dependencies": {
"blocks": [
{
"id": "task-uuid-999",
"title": "API endpoint development",
"dependency_type": "FS"
}
],
"blocked_by": []
},
"created_at": "2025-01-08T10:00:00Z",
"updated_at": "2025-01-10T15:30:00Z"
}
Create Task
POST /v1/boards/{board_id}/tasks
Request Body:
{
"layer_id": "layer-uuid-789",
"section": "To Do",
"title": "Implement user authentication",
"description": "Add OAuth 2.0 authentication flow",
"assignee_id": "user-uuid-abc",
"priority": "high",
"due_date": "2025-01-20",
"estimated_hours": 12.0,
"tags": ["backend", "security", "auth"],
"metadata": {
"custom_fields": {
"component": "auth-service",
"severity": "critical"
}
}
}
Response: Same as Get Task
Update Task
PATCH /v1/tasks/{task_id}
Request Body (partial updates):
{
"section": "In Progress",
"status": "In Progress",
"assignee_id": "user-uuid-xyz",
"actual_hours": 8.5
}
Move Task
POST /v1/tasks/{task_id}/move
Request Body:
{
"section": "Done",
"sort_order": 2048.5,
"layer_id": "layer-uuid-789"
}
Response:
{
"id": "task-uuid-123",
"section": "Done",
"sort_order": 2048.5,
"layer_id": "layer-uuid-789",
"updated_at": "2025-01-10T16:45:00Z"
}
Delete Task
DELETE /v1/tasks/{task_id}
Response:
{
"deleted": true,
"id": "task-uuid-123"
}
Comments
List Comments
GET /v1/tasks/{task_id}/comments
Query Parameters:
limit(optional): Results per page (max: 100)offset(optional): Pagination offset
Response:
{
"data": [
{
"id": "comment-uuid-123",
"task_id": "task-uuid-456",
"user": {
"id": "user-uuid-789",
"name": "Sarah Johnson",
"email": "sarah@example.com",
"avatar_url": "https://..."
},
"content": "Design review completed. Looks great!",
"mentions": ["user-uuid-abc"],
"edited": false,
"created_at": "2025-01-10T14:30:00Z",
"updated_at": "2025-01-10T14:30:00Z"
}
],
"pagination": {
"total": 8,
"limit": 50,
"offset": 0,
"has_more": false
}
}
Create Comment
POST /v1/tasks/{task_id}/comments
Request Body:
{
"content": "Started working on this. ETA is Friday.",
"mentions": ["user-uuid-abc"]
}
Update Comment
PATCH /v1/comments/{comment_id}
Request Body:
{
"content": "Updated comment content"
}
Delete Comment
DELETE /v1/comments/{comment_id}
Layers
List Layers
GET /v1/boards/{board_id}/layers
Query Parameters:
status(optional): Filter by status (active/completed/archived)layer_type(optional): Filter by type (sprint/epic/milestone/phase/custom)
Response:
{
"data": [
{
"id": "layer-uuid-123",
"board_id": "board-uuid-456",
"name": "Sprint 23",
"description": "Q1 Sprint 23",
"layer_type": "sprint",
"status": "active",
"start_date": "2025-01-08",
"end_date": "2025-01-22",
"color": "#3B82F6",
"sort_order": 1,
"metadata": {
"sprint": {
"sprint_number": 23,
"velocity_target": 25
},
"progress": {
"total_tasks": 15,
"completed_tasks": 8,
"completion_percentage": 53
}
},
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-10T12:00:00Z"
}
],
"pagination": {
"total": 3,
"limit": 50,
"offset": 0,
"has_more": false
}
}
Create Layer
POST /v1/boards/{board_id}/layers
Request Body:
{
"name": "Sprint 24",
"description": "Q1 Sprint 24",
"layer_type": "sprint",
"start_date": "2025-01-22",
"end_date": "2025-02-05",
"color": "#3B82F6",
"metadata": {
"sprint": {
"sprint_number": 24,
"velocity_target": 25
}
}
}
Webhooks
Webhooks allow Waymaker to send real-time notifications to your application when events occur.
Setting Up Webhooks
1. Create Webhook Endpoint:
- Navigate to Settings → Webhooks
- Click "Add Webhook"
- Enter endpoint URL (must be HTTPS)
- Select events to subscribe to
- Optionally add secret for verification
2. Verify Endpoint:
// Waymaker sends a verification request
app.post('/webhooks/waymaker', (req, res) => {
if (req.body.type === 'webhook.verification') {
// Echo back the challenge
res.json({ challenge: req.body.challenge });
}
});
3. Handle Events:
app.post('/webhooks/waymaker', (req, res) => {
const event = req.body;
// Verify signature
const signature = req.headers['x-waymaker-signature'];
if (!verifySignature(event, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Process event
switch (event.type) {
case 'task.created':
handleTaskCreated(event.data);
break;
case 'task.updated':
handleTaskUpdated(event.data);
break;
// ... handle other events
}
res.status(200).send('OK');
});
Webhook Security
Signature Verification:
import crypto from 'crypto';
function verifySignature(
payload: any,
signature: string,
secret: string
): boolean {
const computed = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(computed)
);
}
Headers:
X-Waymaker-Signature: sha256=abc123...
X-Waymaker-Delivery-Id: uuid-123
X-Waymaker-Event-Type: task.created
Webhook Events
Task Events
task.created:
{
"type": "task.created",
"id": "event-uuid-123",
"created_at": "2025-01-10T16:00:00Z",
"data": {
"task": {
"id": "task-uuid-456",
"board_id": "board-uuid-789",
"title": "New task",
"section": "To Do",
"assignee_id": "user-uuid-abc",
"created_by": "user-uuid-def"
}
},
"organization_id": "org-uuid-123",
"board_id": "board-uuid-789"
}
task.updated:
{
"type": "task.updated",
"id": "event-uuid-124",
"created_at": "2025-01-10T16:05:00Z",
"data": {
"task": {
"id": "task-uuid-456",
"board_id": "board-uuid-789",
"title": "Updated task title",
"section": "In Progress",
"assignee_id": "user-uuid-abc"
},
"changes": {
"section": {
"from": "To Do",
"to": "In Progress"
},
"title": {
"from": "New task",
"to": "Updated task title"
}
}
},
"organization_id": "org-uuid-123",
"board_id": "board-uuid-789"
}
task.deleted:
{
"type": "task.deleted",
"id": "event-uuid-125",
"created_at": "2025-01-10T16:10:00Z",
"data": {
"task_id": "task-uuid-456",
"board_id": "board-uuid-789",
"deleted_by": "user-uuid-abc"
},
"organization_id": "org-uuid-123",
"board_id": "board-uuid-789"
}
task.moved:
{
"type": "task.moved",
"id": "event-uuid-126",
"created_at": "2025-01-10T16:15:00Z",
"data": {
"task": {
"id": "task-uuid-456",
"board_id": "board-uuid-789",
"title": "Task title"
},
"changes": {
"section": {
"from": "In Progress",
"to": "Done"
},
"sort_order": {
"from": 1024.5,
"to": 2048.75
}
}
},
"organization_id": "org-uuid-123",
"board_id": "board-uuid-789"
}
task.completed:
{
"type": "task.completed",
"id": "event-uuid-127",
"created_at": "2025-01-10T16:20:00Z",
"data": {
"task": {
"id": "task-uuid-456",
"board_id": "board-uuid-789",
"title": "Completed task",
"completed_at": "2025-01-10T16:20:00Z",
"completed_by": "user-uuid-abc",
"cycle_time_hours": 23.5
}
},
"organization_id": "org-uuid-123",
"board_id": "board-uuid-789"
}
Comment Events
comment.created:
{
"type": "comment.created",
"id": "event-uuid-128",
"created_at": "2025-01-10T16:25:00Z",
"data": {
"comment": {
"id": "comment-uuid-789",
"task_id": "task-uuid-456",
"user_id": "user-uuid-abc",
"content": "Comment text here",
"mentions": ["user-uuid-def"]
},
"task": {
"id": "task-uuid-456",
"title": "Task title"
}
},
"organization_id": "org-uuid-123",
"board_id": "board-uuid-789"
}
Board Events
board.created, board.updated, board.deleted:
{
"type": "board.created",
"id": "event-uuid-129",
"created_at": "2025-01-10T16:30:00Z",
"data": {
"board": {
"id": "board-uuid-789",
"organization_id": "org-uuid-123",
"name": "New Board",
"created_by": "user-uuid-abc"
}
},
"organization_id": "org-uuid-123"
}
Webhook Retry Logic
Failed Delivery:
- Waymaker retries failed webhooks with exponential backoff
- Retry schedule: 15s, 1m, 5m, 15m, 1h, 6h
- After 6 failed attempts, webhook is marked as failed
- Failed webhooks can be manually retried from Settings
Retry Headers:
X-Waymaker-Retry-Count: 2
X-Waymaker-Retry-Max: 6
Webhook Best Practices
✅ Respond quickly - Acknowledge receipt with 200 status ASAP ✅ Process async - Queue events for background processing ✅ Verify signatures - Always validate webhook signatures ✅ Handle duplicates - Use event IDs to deduplicate ✅ Log failures - Monitor and alert on webhook errors ✅ Use HTTPS - Webhook endpoints must use HTTPS ✅ Implement retries - Handle transient failures gracefully
Error Handling
Error Response Format
{
"error": {
"code": "validation_error",
"message": "Invalid request parameters",
"details": [
{
"field": "assignee_id",
"message": "User does not have access to this board"
}
]
},
"request_id": "req-uuid-123"
}
Common Error Codes
4xx Client Errors:
400 bad_request: Invalid request format401 unauthorized: Missing or invalid API key403 forbidden: Insufficient permissions404 not_found: Resource not found409 conflict: Resource conflict (e.g., duplicate)422 validation_error: Request validation failed429 rate_limit_exceeded: Too many requests
5xx Server Errors:
500 internal_server_error: Server error502 bad_gateway: Gateway error503 service_unavailable: Temporary unavailable504 gateway_timeout: Request timeout
Handling Errors
async function createTask(boardId: string, taskData: any) {
try {
const response = await fetch(
`https://api.waymakerone.com/v1/boards/${boardId}/tasks`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(taskData),
}
);
if (!response.ok) {
const error = await response.json();
switch (response.status) {
case 401:
throw new Error('Invalid API key');
case 403:
throw new Error('Insufficient permissions');
case 422:
throw new Error(`Validation error: ${error.error.details}`);
case 429:
// Handle rate limit
const retryAfter = response.headers.get('X-RateLimit-Retry-After');
await sleep(parseInt(retryAfter) * 1000);
return createTask(boardId, taskData); // Retry
default:
throw new Error(`API error: ${error.error.message}`);
}
}
return await response.json();
} catch (error) {
console.error('Failed to create task:', error);
throw error;
}
}
Example Integrations
GitHub Integration
Automatically create tasks from GitHub issues:
// GitHub webhook handler
app.post('/webhooks/github', async (req, res) => {
const event = req.body;
if (event.action === 'opened' && event.issue) {
// Create Waymaker task from GitHub issue
await createTask(BOARD_ID, {
title: event.issue.title,
description: event.issue.body,
tags: ['github', 'issue'],
metadata: {
custom_fields: {
github_issue_number: event.issue.number,
github_url: event.issue.html_url,
}
}
});
}
res.status(200).send('OK');
});
Slack Integration
Post task updates to Slack:
// Waymaker webhook handler
app.post('/webhooks/waymaker', async (req, res) => {
const event = req.body;
if (event.type === 'task.completed') {
const task = event.data.task;
// Post to Slack
await postToSlack({
channel: '#project-updates',
text: `✅ Task completed: ${task.title}`,
attachments: [
{
color: 'good',
fields: [
{
title: 'Completed By',
value: task.completed_by_name,
short: true
},
{
title: 'Cycle Time',
value: `${task.cycle_time_hours} hours`,
short: true
}
]
}
]
});
}
res.status(200).send('OK');
});
CI/CD Integration
Update task status from CI/CD pipeline:
# .github/workflows/deploy.yml
- name: Update Waymaker Task
run: |
curl -X PATCH \
https://api.waymakerone.com/v1/tasks/${{ env.TASK_ID }} \
-H 'Authorization: Bearer ${{ secrets.WAYMAKER_API_KEY }}' \
-H 'Content-Type: application/json' \
-d '{
"section": "Done",
"status": "Done",
"metadata": {
"custom_fields": {
"deployed_at": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",
"deployment_url": "https://app.example.com"
}
}
}'
SDK and Libraries
Official SDKs:
- JavaScript/TypeScript:
npm install @waymaker/sdk - Python:
pip install waymaker-sdk - Go:
go get github.com/waymaker/waymaker-go
TypeScript Example:
import { WaymakerClient } from '@waymaker/sdk';
const client = new WaymakerClient({
apiKey: process.env.WAYMAKER_API_KEY,
});
// Create a task
const task = await client.tasks.create(boardId, {
title: 'Implement feature X',
section: 'To Do',
priority: 'high',
});
// Update a task
await client.tasks.update(task.id, {
section: 'In Progress',
assignee_id: userId,
});
// Subscribe to webhooks
client.webhooks.on('task.completed', (event) => {
console.log('Task completed:', event.data.task.title);
});
Best Practices
API Usage
✅ Cache responses where appropriate ✅ Use pagination for large datasets ✅ Implement retry logic with exponential backoff ✅ Handle rate limits gracefully ✅ Validate input before API calls ✅ Store API keys securely (environment variables) ✅ Monitor API usage and set up alerts ✅ Use webhooks instead of polling when possible
Webhook Implementation
✅ Respond quickly (< 3 seconds) ✅ Process async (use job queues) ✅ Verify signatures on all incoming webhooks ✅ Handle duplicates using event IDs ✅ Implement idempotency in event handlers ✅ Log all events for debugging ✅ Monitor failures and set up alerts ✅ Test thoroughly with webhook testing tools
Conclusion
Waymaker's API and webhook system enables:
- Custom integrations with your existing tools
- Automated workflows reducing manual work
- Real-time updates across systems
- Custom reporting and analytics
- Extended functionality beyond the UI
Build powerful integrations that connect Waymaker taskboards with your entire development ecosystem.
Related Resources
- Data Model - Understanding the taskboard data structure
- Security - API security and best practices
- Developer API Reference - Complete API documentation
Last updated: January 10, 2025