Get the FREE Ultimate OpenClaw Setup Guide →
b

Motion

Verified

@byungkyu

npx machina-cli add skill @byungkyu/motion --openclaw
Files (1)
SKILL.md
12.5 KB

Motion

Access the Motion API with managed OAuth authentication. Manage tasks, projects, workspaces, comments, and recurring tasks with full CRUD operations.

Quick Start

# List tasks
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/motion/v1/tasks')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Base URL

https://gateway.maton.ai/motion/{native-api-path}

Replace {native-api-path} with the actual Motion API endpoint path. The gateway proxies requests to api.usemotion.com and automatically injects your OAuth token.

Authentication

All requests require the Maton API key in the Authorization header:

Authorization: Bearer $MATON_API_KEY

Environment Variable: Set your API key as MATON_API_KEY:

export MATON_API_KEY="YOUR_API_KEY"

Getting Your API Key

  1. Sign in or create an account at maton.ai
  2. Go to maton.ai/settings
  3. Copy your API key

Connection Management

Manage your Motion OAuth connections at https://ctrl.maton.ai.

List Connections

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections?app=motion&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Create Connection

python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'motion'}).encode()
req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Get Connection

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Response:

{
  "connection": {
    "connection_id": "21fd90f9-5935-43cd-b6c8-bde9d915ca80",
    "status": "ACTIVE",
    "creation_time": "2025-12-08T07:20:53.488460Z",
    "last_updated_time": "2026-01-31T20:03:32.593153Z",
    "url": "https://connect.maton.ai/?session_token=...",
    "app": "motion",
    "metadata": {}
  }
}

Open the returned url in a browser to complete OAuth authorization.

Delete Connection

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Specifying Connection

If you have multiple Motion connections, specify which one to use with the Maton-Connection header:

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/motion/v1/tasks')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '21fd90f9-5935-43cd-b6c8-bde9d915ca80')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

If omitted, the gateway uses the default (oldest) active connection.

API Reference

Task Operations

List Tasks

GET /motion/v1/tasks

Query Parameters:

  • workspaceId (string) - Filter by workspace
  • projectId (string) - Filter by project
  • assigneeId (string) - Filter by assignee
  • status (array) - Filter by status (cannot combine with includeAllStatuses)
  • includeAllStatuses (boolean) - Return tasks across all statuses
  • label (string) - Filter by label
  • name (string) - Search task names (case-insensitive)
  • cursor (string) - Pagination cursor

Example:

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/motion/v1/tasks?workspaceId=WORKSPACE_ID')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Get Task

GET /motion/v1/tasks/{taskId}

Create Task

POST /motion/v1/tasks
Content-Type: application/json

{
  "name": "Task name",
  "workspaceId": "WORKSPACE_ID",
  "dueDate": "2024-03-15T10:00:00Z",
  "duration": 60,
  "priority": "HIGH",
  "description": "Task description in markdown",
  "projectId": "PROJECT_ID",
  "assigneeId": "USER_ID",
  "labels": ["label1", "label2"],
  "autoScheduled": {
    "startDate": "2024-03-14T09:00:00Z",
    "deadlineType": "SOFT",
    "schedule": "Work Hours"
  }
}

Required Fields:

  • name (string) - Task title
  • workspaceId (string) - Workspace ID

Optional Fields:

  • dueDate (datetime, ISO 8601) - Task deadline (required for scheduled tasks)
  • duration (string | number) - "NONE", "REMINDER", or minutes (integer > 0)
  • status (string) - Defaults to workspace default status
  • projectId (string) - Associated project
  • description (string) - GitHub Flavored Markdown supported
  • priority (string) - ASAP, HIGH, MEDIUM, or LOW
  • labels (array) - Label names to add
  • assigneeId (string) - User ID for task assignment
  • autoScheduled (object) - Auto-scheduling settings with startDate, deadlineType (HARD, SOFT, NONE), and schedule

Example:

python <<'EOF'
import urllib.request, os, json
data = json.dumps({
    'name': 'New task',
    'workspaceId': 'WORKSPACE_ID',
    'priority': 'HIGH',
    'duration': 30
}).encode()
req = urllib.request.Request('https://gateway.maton.ai/motion/v1/tasks', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Update Task

PATCH /motion/v1/tasks/{taskId}
Content-Type: application/json

{
  "name": "Updated task name",
  "status": "Completed",
  "priority": "LOW"
}

Delete Task

DELETE /motion/v1/tasks/{taskId}

Move Task

POST /motion/v1/tasks/{taskId}/move
Content-Type: application/json

{
  "workspaceId": "NEW_WORKSPACE_ID"
}

Unassign Task

POST /motion/v1/tasks/{taskId}/unassign

Project Operations

List Projects

GET /motion/v1/projects?workspaceId={workspaceId}

Query Parameters:

  • workspaceId (string, required) - Workspace ID
  • cursor (string) - Pagination cursor

Get Project

GET /motion/v1/projects/{projectId}

Create Project

POST /motion/v1/projects
Content-Type: application/json

{
  "name": "Project name",
  "workspaceId": "WORKSPACE_ID",
  "description": "Project description",
  "dueDate": "2024-06-30T00:00:00Z",
  "priority": "HIGH",
  "labels": ["label1"]
}

Required Fields:

  • name (string) - Project name
  • workspaceId (string) - Workspace ID

Optional Fields:

  • dueDate (datetime, ISO 8601) - Project deadline
  • description (string) - HTML input accepted
  • labels (array) - Label names
  • priority (string) - ASAP, HIGH, MEDIUM (default), or LOW
  • projectDefinitionId (string) - Template ID (requires stages array if provided)
  • stages (array) - Stage objects for project templates

Workspace Operations

List Workspaces

GET /motion/v1/workspaces

User Operations

List Users

GET /motion/v1/users?workspaceId={workspaceId}

Query Parameters:

  • workspaceId (string) - Workspace ID (required if no teamId)
  • teamId (string) - Team ID (required if no workspaceId)

Note: You must provide either workspaceId or teamId.

Get Current User

GET /motion/v1/users/me

Comment Operations

List Comments

GET /motion/v1/comments?taskId={taskId}

Query Parameters:

  • taskId (string, required) - Filter comments by task
  • cursor (string) - Pagination cursor

Create Comment

POST /motion/v1/comments
Content-Type: application/json

{
  "taskId": "TASK_ID",
  "content": "Comment in GitHub Flavored Markdown"
}

Required Fields:

  • taskId (string) - Task to comment on

Optional Fields:

  • content (string) - Comment content in GitHub Flavored Markdown

Recurring Task Operations

List Recurring Tasks

GET /motion/v1/recurring-tasks?workspaceId={workspaceId}

Query Parameters:

  • workspaceId (string, required) - Filter by workspace
  • cursor (string) - Pagination cursor

Create Recurring Task

POST /motion/v1/recurring-tasks
Content-Type: application/json

{
  "name": "Weekly review",
  "workspaceId": "WORKSPACE_ID",
  "frequency": "weekly"
}

Delete Recurring Task

DELETE /motion/v1/recurring-tasks/{recurringTaskId}

Schedule Operations

List Schedules

GET /motion/v1/schedules

Status Operations

List Statuses

GET /motion/v1/statuses?workspaceId={workspaceId}

Query Parameters:

  • workspaceId (string, required) - Filter by workspace

Custom Field Operations

List Custom Fields

GET /motion/v1/custom-fields

Create Custom Field

POST /motion/v1/custom-fields
Content-Type: application/json

{
  "name": "Field name",
  "type": "text"
}

Delete Custom Field

DELETE /motion/v1/custom-fields/{customFieldId}

Add Custom Field to Project

POST /motion/v1/custom-fields/{customFieldId}/project
Content-Type: application/json

{
  "projectId": "PROJECT_ID"
}

Add Custom Field to Task

POST /motion/v1/custom-fields/{customFieldId}/task
Content-Type: application/json

{
  "taskId": "TASK_ID"
}

Remove Custom Field from Project

DELETE /motion/v1/custom-fields/{customFieldId}/project

Remove Custom Field from Task

DELETE /motion/v1/custom-fields/{customFieldId}/task

Pagination

Motion uses cursor-based pagination:

GET /motion/v1/tasks?cursor=CURSOR_VALUE

Response includes pagination metadata:

{
  "tasks": [...],
  "meta": {
    "nextCursor": "abc123",
    "pageSize": 20
  }
}

Use the nextCursor value in subsequent requests to retrieve more results.

Code Examples

JavaScript

const response = await fetch(
  'https://gateway.maton.ai/motion/v1/tasks',
  {
    headers: {
      'Authorization': `Bearer ${process.env.MATON_API_KEY}`
    }
  }
);
const data = await response.json();

Python

import os
import requests

response = requests.get(
    'https://gateway.maton.ai/motion/v1/tasks',
    headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
data = response.json()

Notes

  • All timestamps use ISO 8601 format
  • Task descriptions support GitHub Flavored Markdown
  • Project descriptions accept HTML input
  • Priority values: ASAP, HIGH, MEDIUM, LOW
  • Deadline types for auto-scheduling: HARD, SOFT, NONE
  • Rate limits: 12 req/min (Individual), 120 req/min (Team)
  • IMPORTANT: When using curl commands, use curl -g when URLs contain brackets to disable glob parsing
  • IMPORTANT: When piping curl output to jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments

Error Handling

StatusMeaning
400Missing Motion connection or invalid request
401Invalid or missing Maton API key
429Rate limited
4xx/5xxPassthrough error from Motion API

Resources

Source

git clone https://clawhub.ai/byungkyu/motionView on GitHub

Overview

Motion API integrates with managed OAuth to let you create, read, update, and delete tasks, projects, workspaces, and more. It supports CRuD operations and scheduled queries via a gateway that injects OAuth tokens, making secure automation for Motion seamless.

How This Skill Works

Requests target the Motion gateway at https://gateway.maton.ai/motion/{native-api-path} with an Authorization: Bearer MATON_API_KEY header. The gateway proxies to api.usemotion.com and handles token injection. When multiple Motion connections exist, specify the desired account with the Maton-Connection header to route requests to the correct OAuth session.

When to Use It

  • Create, update, or delete tasks and projects in Motion via the API.
  • Query scheduled work and retrieve timelines across workspaces.
  • Manage workspaces and recurring tasks using full CRUD operations.
  • Integrate Motion into backend services with managed OAuth via the gateway.
  • Specify the correct Motion connection using Maton-Connection when multiple connections exist.

Quick Start

  1. Step 1: Export your API key and set MATON_API_KEY in your environment (e.g., export MATON_API_KEY="YOUR_API_KEY").
  2. Step 2: Call a Motion endpoint through the gateway, for example: curl -H "Authorization: Bearer $MATON_API_KEY" https://gateway.maton.ai/motion/v1/tasks.
  3. Step 3: Replace {native-api-path} in the Base URL with your target endpoint path and handle the JSON response.

Best Practices

  • Always include Authorization: Bearer $MATON_API_KEY in every request.
  • Use the gateway base URL and substitute {native-api-path} with the target Motion endpoint.
  • Securely store and rotate MATON_API_KEY; use environment variables like MATON_API_KEY.
  • Use the Maton-Connection header to select the correct Motion connection when multiple connections exist.
  • Handle responses and errors gracefully, and paginate list endpoints as needed.

Example Use Cases

  • List tasks via GET https://gateway.maton.ai/motion/v1/tasks with Authorization header and MATON_API_KEY.
  • Create a new task by POSTing to https://gateway.maton.ai/motion/v1/tasks with task payload and MATON_API_KEY.
  • Update a task or project via PUT/PATCH to /motion/v1/tasks/{id} or /motion/v1/projects/{id}.
  • List active connections for Motion with GET https://ctrl.maton.ai/connections?app=motion&status=ACTIVE.
  • Get a specific connection by ID to inspect status and metadata.

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers