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:

  1. Navigate to Settings → API Keys
  2. Click "Generate New API Key"
  3. Name your key (e.g., "CI/CD Integration")
  4. Copy the key (shown only once)
  5. 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 UUID
  • archived (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 layer
  • assignee_id (optional): Filter by assignee
  • status (optional): Filter by status
  • priority (optional): Filter by priority
  • tags (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 offset
  • sort (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 include
    • comments: Include task comments
    • attachments: Include task attachments
    • dependencies: Include task dependencies
    • all: 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 format
  • 401 unauthorized: Missing or invalid API key
  • 403 forbidden: Insufficient permissions
  • 404 not_found: Resource not found
  • 409 conflict: Resource conflict (e.g., duplicate)
  • 422 validation_error: Request validation failed
  • 429 rate_limit_exceeded: Too many requests

5xx Server Errors:

  • 500 internal_server_error: Server error
  • 502 bad_gateway: Gateway error
  • 503 service_unavailable: Temporary unavailable
  • 504 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


Last updated: January 10, 2025