Motion API
Vollständiger Client für die Motion (usemotion.com) REST-API – alle 27 dokumentierten Endpunkte für
Aufgaben, Projekte, wiederkehrende Aufgaben, Kommentare, benutzerdefinierte Felder, Benutzer, Arbeitsbereiche, Status und
Zeitpläne, plus eine raw-Ausweichmöglichkeit für alles, was noch nicht dokumentiert ist.
Wann dieses Skill verwendet werden sollte
Verwenden Sie es immer dann, wenn die Arbeit Motion betrifft: Lesen oder Erstellen von Aufgaben, Auflisten von Projekten, Posten von Kommentaren zu Aufgaben, Verwalten wiederkehrender Aufgaben oder Lesen von Arbeitsbereichs-Status, Benutzern und Zeitplänen.
Anmeldeinformationen
Eine Anmeldeinformation, MOTION_API_KEY. Die Plattform injiziert sie als Umgebungsvariable, wenn
ein Skript über RunWithCredentials ausgeführt wird – übergeben Sie niemals einen Schlüssel in der Befehlszeile und geben Sie ihn
niemals aus oder echoen Sie ihn.
Holen Sie sich einen Schlüssel in Motion unter Einstellungen → API. Motion zeigt ihn nur einmal an, also kopieren Sie ihn sofort. Wenn Aufrufe 401 zurückgeben, wurde der Schlüssel widerrufen oder neu generiert und muss ersetzt werden.
Hinweis: Bei der Proxy-Modus-Auslieferung von Anmeldeinformationen enthält die Umgebungsvariable einen nicht geheimen Platzhalter und
der tatsächliche Wert wird in Anfragen an api.usemotion.com injiziert. Ein neu gespeicherter Schlüssel
kann einige Minuten brauchen, um sich zu verbreiten; eine sofortige 401, die später erfolgreich ist, ist Verbreitung,
kein ungültiger Schlüssel.
Von der API befolgte Konventionen
Dies sind die Fakten, die den Unterschied zwischen einem funktionierenden und einem nicht funktionierenden Aufruf ausmachen.
| Sache | Wert |
|---|---|
| Basis-URL | https://api.usemotion.com |
| Auth-Header | X-API-Key: <key> |
| Health-Check | GET /v1/users/me – gibt den Besitzer des Schlüssels zurück |
| Pfad-Präfixe | /v1/ für alles außer benutzerdefinierten Feldern, die unter /beta/ liegen |
| Ratenbegrenzungen | 12 Anfragen/min (einzeln), bis zu 120 (Teams), höher für Enterprise |
| Beschreibungen | Github Flavored Markdown |
| Prioritätswerte | ASAP, HOCH, MITTEL, NIEDRIG (wiederkehrende Aufgaben: nur HOCH/MITTEL) |
| Frist-Typen | HART, WEICH, KEINE (wiederkehrende Aufgaben: nur HART/WEICH) |
Paginierung. Listen-Endpunkte akzeptieren einen cursor und geben einen Umschlag zurück:
{ "meta": { "nextCursor": "…", "pageSize": 25 }, "tasks": [ … ] }
Der Umschlagschlüssel ist meta, und das Feld für die nächste Seite ist nextCursor. Übergeben Sie --all bei einem beliebigen
Listenbefehl und das Skript folgt dem Cursor für Sie und gibt ein flaches Array zurück.
--all stoppt nach 100 Seiten und schlägt dann fehl, sodass eine außer Kontrolle geratene Abfrage einen Lauf nicht aufhängen kann – grenzen Sie
die Abfrage ein, wenn Sie dies sehen. Und wenn eine Seite weder ein JSON-Objekt noch ein Array ist (abgeschnitten oder
eine Gateway-Fehlerseite), weigert sich der Durchlauf, anstatt das zurückzugeben, was er hat: Eine unvollständige Liste,
die vollständig aussieht, ist schlimmer als ein Fehler.
Zwei Listen-Endpunkte geben ein bloßes Array ohne Paginierung zurück – GET /v1/statuses und
GET /beta/workspaces/{id}/custom-fields. Alles andere ist umschlossen.
Fehler. Nicht-2xx-Antworten enthalten {"message", "error", "statusCode"}. Die Skripte geben dies
als JSON auf stderr aus und beenden mit einem Fehlercode ungleich Null. 429 wird mit Backoff unter Berücksichtigung von
Retry-After wiederholt; 400, 401, 403 und 404 werden sofort gemeldet und niemals wiederholt.
Validierungsfehler enthalten ein feldbezogenes errors[]-Array; der Client hängt diese Nachrichten an,
damit der eigentliche Grund sichtbar ist.
Ein User-Agent ist obligatorisch. Moutons Edge blockiert die Standard-Signatur Python-urllib/x.y
mit einem Cloudflare-403 (browser_signature_banned), bevor die Anfrage die API erreicht.
Der Client sendet immer motion-api-skill/1.0; wenn Sie Ihre eigene Anfrage gegen diese
API schreiben, setzen Sie explizit einen User-Agent, sonst erhalten Sie einen verwirrenden 403 anstelle einer echten
Antwort.
Boolesche Abfrageparameter müssen kleingeschrieben sein. Motion analysiert Abfragezeichenfolgen als Text, daher muss ein
boolescher Filter das Literal true sein, nicht Pythons True. Dies falsch zu machen, ist
keine stille Nicht-Operation: Die API antwortet mit einem verwirrenden 400, der über den entgegengesetzten Wert spricht
(siehe den Abschnitt Live-Unterschiede unten). Der Client sendet immer kleingeschriebene Literale.
Befehlsreferenz
Jeder Befehl gibt JSON auf stdout aus. python3 motion.py <gruppe> --help listet die Flags auf.
Aufgaben
| Befehl | Endpunkt |
|---|---|
tasks list | GET /v1/tasks |
tasks get <task_id> | GET /v1/tasks/{id} |
tasks create | POST /v1/tasks |
tasks update <task_id> | PATCH /v1/tasks/{id} |
tasks move <task_id> --workspace-id … | PATCH /v1/tasks/{id}/move |
tasks delete <task_id> --yes | DELETE /v1/tasks/{id} |
tasks unassign <task_id> --yes | DELETE /v1/tasks/{id}/assignee |
tasks list Filter: --assignee-id, --project-id, --workspace-id, --name
(groß-/kleinschreibungsunabhängige Teilzeichenfolge), --label (einzeln, ein Label-Name), --status (wiederholbar),
--include-all-statuses. --status und --include-all-statuses schließen sich gegenseitig aus –
beides zu senden, wird von der API abgelehnt, und die CLI weigert sich frühzeitig mit dieser Nachricht, anstatt
eine Anfrage für einen garantierten 400 zu verschwenden.
--include-all-statuses ist die Möglichkeit, eine Aufgabe zu sehen, die über ihren Arbeitsbereichs-Standard hinausgegangen ist
(z. B. alles, was in „Backlog" oder „In Review" sitzt); ohne sie gibt GET /v1/tasks nur
den Standard-Status zurück und die Liste sieht leer aus. Die Kombination mit --all gibt jede
Aufgabe zurück, die jemandem zugewiesen ist, über alle Status hinweg.
tasks create / tasks update akzeptieren die gleichen Felder: --name, --workspace-id,
--due-date (ISO 8601; erforderlich für geplante Aufgaben), --duration, --status,
--project-id, --description, --priority, --label (wiederholbar), --assignee-id.
--duration akzeptiert eine ganze Anzahl von Minuten oder die Zeichenfolgen KEINE / ERINNERUNG
(groß-/kleinschreibungsunabhängig bei der Eingabe, normalisiert zu Großbuchstaben).
Die automatische Planung ist dreiwertig, und der Unterschied ist wichtig:
- Beide Flags weglassen → das Feld wird aus der Anfrage vollständig weggelassen (unverändert)
--auto-scheduled '{"deadlineType":"HART"}'→ schaltet sie ein; verschachtelte Felder sindstartDate,deadlineType(HART/WEICH/KEINE) undschedule(StandardArbeitszeiten)--auto-scheduled-off→ sendet explizitnull, schaltet sie aus
Der Status der Aufgabe muss die automatische Planung aktiviert haben, sonst lehnt die API ab.
Eine Aufgabenantwort sieht so aus – gekürzt auf die Felder, von denen der Kalender-Workflow unten abhängt:
{
"id": "tsk_123",
"name": "Q4-Plan entwerfen",
"description": "Skizzieren Sie die drei Szenarien.",
"status": { "name": "In Bearbeitung", "isResolvedStatus": false },
"priority": "HOCH",
"labels": ["q4"],
"assignees": [{ "id": "usr_1", "name": "Sam Patel" }],
"project": { "id": "prj_1", "name": "Planung" },
"dueDate": "2026-11-01T17:00:00.000Z",
"duration": 45,
"scheduledStart": "2026-10-28T09:00:00.000Z",
"startOn": "2026-10-28",
"completedTime": null
}
Lesen Sie es so: status ist ein Objekt, keine Zeichenfolge – der Filter, den Sie möchten, ist
status.isResolvedStatus, der true wird, sobald eine Aufgabe abgeschlossen oder abgebrochen ist.
assignees und labels sind Arrays; project ist ein Objekt oder null. scheduledStart
und dueDate sind UTC; startOn ist ein bloßes Datum.
Es gibt keinen Kalender-Endpunkt. Die Position einer Aufgabe im Kalender ist ihr scheduledStart
(UTC ISO 8601), mit duration in Minuten und startOn als einfaches Datum. Um zu beantworten „was kommt
als nächstes", rufen Sie die Aufgaben ab und sortieren Sie nach scheduledStart – suchen Sie nicht nach einem Zeitplan-
Endpunkt, der Ereignisse zurückgibt, denn schedules list gibt nur die Arbeitszeitenfenster
zurück (siehe unten), nicht die gebuchten Elemente. Filtern Sie Aufgaben mit status.isResolvedStatus heraus, um
bereits abgeschlossene oder abgebrochene auszuschließen.
Projekte
| Befehl | Endpunkt |
|---|---|
projects list [--workspace-id …] | GET /v1/projects |
projects get <project_id> | GET /v1/projects/{id} |
projects create --name … --workspace-id … | POST /v1/projects |
projects create akzeptiert auch --due-date, --description (HTML akzeptiert), --label
(wiederholbar), --priority (Standard ist MITTEL serverseitig) und das Vorlagenpaar
--project-definition-id + --stages. Phasen müssen genau mit der Reihenfolge und Anzahl der Definition
übereinstimmen, sonst gibt die API 400 zurück. Für lange Phasen-Arrays verwenden Sie --stages @stages.json.
Die CLI erzwingt das Paar nicht; die API lehnt eine Phasenliste ohne eine Definitions-ID ab.
Wiederkehrende Aufgaben
| Befehl | Endpunkt |
|---|---|
recurring-tasks list --workspace-id … | GET /v1/recurring-tasks |
recurring-tasks create | POST /v1/recurring-tasks |
recurring-tasks delete <id> --yes | DELETE /v1/recurring-tasks/{id} |
recurring-tasks create erfordert --frequency, --name, --workspace-id und
--assignee-id. Optional: --deadline-type (nur HART/WEICH – KEINE wird hier abgelehnt),
--duration (Minuten als ganze Zahl oder ERINNERUNG; KEINE wird an diesem Endpunkt nicht akzeptiert),
--starting-on, --ideal-time (HH:mm), --schedule (Standard Arbeitszeiten),
--description, --priority (nur HOCH/MITTEL).
--starting-on wird genau wie angegeben an die API gesendet – keine Kürzung.
--frequency ist eine Zeichenfolge in Moutons eigener DSL, kein Objekt. Das bringt Leute
durcheinander. Das Vokabular ist dokumentiert unter https://docs.usemotion.com/cookbooks/frequency/:
- Tagescodes:
MO,DI,MI,DO,FR,SA,SO - Täglich:
daily_every_day,daily_every_week_day,daily_specific_days_[MO, DI, FR] - Wöchentlich:
weekly_any_day,weekly_any_week_day,weekly_specific_days_[MO, FR] - Zweiwöchentlich:
biweekly_first_week_any_day,biweekly_first_week_specific_days_[MO, DI],biweekly_second_week_any_week_day - Monatlich nach Wochentag:
monthly_first_MO,monthly_second_DI,monthly_last_FR - Monatlich nach Datum:
monthly_1,monthly_15,monthly_31(ein Tag außerhalb des Bereichs fällt zurück auf den letzten Tag des Monats) - Monatlich nach Woche:
monthly_any_day_first_week,monthly_any_week_day_last_week,monthly_last_day_of_month - Vierteljährlich:
quarterly_first_day,quarterly_last_week_day,quarterly_any_day_first_week
Ein Tagesarray muss immer mit einem Häufigkeitstyp gepaart sein – [MO, FR] allein ist nicht gültig.
Ein vollständiger Aufruf, da die Häufigkeitszeichenfolge der schwierige Teil ist:
python3 motion.py recurring-tasks create \
--name "Wöchentliche Überprüfung" --workspace-id ws_1 --assignee-id usr_1 \
--frequency "weekly_specific_days_[MO,FR]" \
--deadline-type WEICH --duration 30 --ideal-time 16:00 \
--schedule "Arbeitszeiten" --priority MITTEL
Beachten Sie die engeren Mengen hier: Wiederkehrende Aufgaben akzeptieren nur HOCH/MITTEL-Priorität und nur
HART/WEICH-Fristtypen, während der Rest der API auch ASAP/NIEDRIG und KEINE zulässt.
Die CLI erzwingt beides.
Kommentare
| Befehl | Endpunkt |
|---|---|
comments list --task-id … | GET /v1/comments |
comments create --task-id … [--content …] | POST /v1/comments |
--content ist Github Flavored Markdown auf dem Weg hinein und kommt als HTML zurück. Es ist
optional – ohne --content trägt der Anforderungstext nur die Aufgaben-ID. Ob Motion
einen leeren Kommentar akzeptiert, ist nicht verifiziert; übergeben Sie --content, wenn Sie etwas sagen möchten.
Benutzerdefinierte Felder – beachten Sie das Präfix /beta/
| Befehl | Endpunkt |
|---|---|
custom-fields list --workspace-id … | GET /beta/workspaces/{workspaceId}/custom-fields |
custom-fields create --workspace-id … --type … --name … | POST /beta/workspaces/{workspaceId}/custom-fields |
custom-fields delete <id> --workspace-id … --yes | DELETE /beta/workspaces/{workspaceId}/custom-fields/{id} |
custom-field-values add-task <task_id> … | POST /beta/custom-field-values/task/{taskId} |
custom-field-values add-project <project_id> … | POST /beta/custom-field-values/project/{projectId} |
custom-field-values delete-from-task <task_id> <value_id> --yes | DELETE /beta/custom-field-values/task/{taskId}/custom-fields/{valueId} |
custom-field-values delete-from-project <project_id> <value_id> --yes | DELETE /beta/custom-field-values/project/{projectId}/custom-fields/{valueId} |
Die 12 benutzerdefinierten Feldtypen, genau wie buchstabiert: text, url, date, person,
multiPerson, phone, select, multiSelect, number, email, checkbox, relatedTo.
Das Setzen eines Werts erfordert --custom-field-instance-id (das Feld im Arbeitsbereich), --type,
und --value. --value ist JSON, also zitieren Sie es korrekt: --value '"hallo"' für eine Zeichenfolge,
--value '42' für eine Zahl, --value '["A","B"]' für eine Mehrfachauswahl, --value 'true' für
ein Kontrollkästchen.
python3 motion.py custom-field-values add-task tsk_123 \
--custom-field-instance-id cfi_1 --type select --value '"Alpha"'
custom-fields create erwartet --metadata als JSON – format (plain/formatted/percent,
nur Zahlen), toggle für Kontrollkästchen und options für Auswahlfelder:
--metadata '{"options":[{"id":"a","value":"Alpha","color":"#ff0000"}]}'
Benutzer, Arbeitsbereiche, Status, Zeitpläne
| Befehl | Endpunkt |
|---|---|
me | GET /v1/users/me |
users list [--workspace-id …] [--team-id …] | GET /v1/users |
workspaces list [--ids …] | GET /v1/workspaces |
statuses list [--workspace-id …] | GET /v1/statuses |
schedules list | GET /v1/schedules |
workspaces list --ids ist wiederholbar und --all folgt dem Cursor.
users list muss eingegrenzt werden. Übergeben Sie --workspace-id oder --team-id; das Skript weigert sich
bei einem uneingeschränkten Aufruf frühzeitig mit dieser Nachricht, anstatt eine Anfrage für den 400 zu verschwenden, den die API
zurückgibt. Um alle aufzulisten, durchlaufen Sie Ihre Arbeitsbereiche.
schedules list gibt Arbeitszeitenfenster zurück, keine Ereignisse. Jeder Zeitplan hat seine eigene
timezone und ein pro-Tag-Array von {start, end}-Blöcken – und ein Tag kann mehrere
Blöcke enthalten (z. B. ein Schulweg-Zeitplan mit einem Morgen- und einem Abendblock). Lesen Sie dies nicht als
„Der Benutzer hat einen Arbeitsblock pro Tag" und behandeln Sie es nicht als Kalender; für das, was
tatsächlich gebucht ist, lesen Sie die scheduledStart-Werte der Aufgaben.
Raw-Ausweichmöglichkeit
python3 motion.py raw GET /v1/tasks --query status=Todo --query status=Doing
python3 motion.py raw GET /v1/tasks --query assigneeId=u1 --query includeAllStatuses=true --all
python3 motion.py raw POST /v1/comments --body '{"taskId":"t1","content":"hi"}'
python3 motion.py raw DELETE /v1/tasks/t1 --yes
Verwenden Sie dies für alles, was die benannten Befehle nicht abdecken. --query KEY=VALUE ist wiederholbar und das Wiederholen des
…
[gekürzt für die Übersetzung]