@wspc/cli 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/spec/openapi.json CHANGED
@@ -1578,9 +1578,10 @@
1578
1578
  "provider": {
1579
1579
  "type": "string",
1580
1580
  "enum": [
1581
- "cloudflare-email-service"
1581
+ "cloudflare-email-service",
1582
+ "pete-mail"
1582
1583
  ],
1583
- "description": "Send provider. Currently always `cloudflare-email-service`."
1584
+ "description": "Send provider used for this outbound email."
1584
1585
  },
1585
1586
  "provider_message_id": {
1586
1587
  "type": "string",
@@ -1828,6 +1829,57 @@
1828
1829
  }
1829
1830
  ]
1830
1831
  },
1832
+ "CreateCommentBody": {
1833
+ "type": "object",
1834
+ "properties": {
1835
+ "content": {
1836
+ "type": "string",
1837
+ "minLength": 1,
1838
+ "maxLength": 10000
1839
+ }
1840
+ },
1841
+ "required": [
1842
+ "content"
1843
+ ]
1844
+ },
1845
+ "Comment": {
1846
+ "type": "object",
1847
+ "properties": {
1848
+ "id": {
1849
+ "type": "string"
1850
+ },
1851
+ "todo_id": {
1852
+ "type": "string"
1853
+ },
1854
+ "user_id": {
1855
+ "type": "string"
1856
+ },
1857
+ "org_id": {
1858
+ "type": "string"
1859
+ },
1860
+ "content": {
1861
+ "type": "string"
1862
+ },
1863
+ "created_at": {
1864
+ "type": "integer"
1865
+ },
1866
+ "updated_at": {
1867
+ "type": "integer"
1868
+ },
1869
+ "deleted_at": {
1870
+ "type": "integer"
1871
+ }
1872
+ },
1873
+ "required": [
1874
+ "id",
1875
+ "todo_id",
1876
+ "user_id",
1877
+ "org_id",
1878
+ "content",
1879
+ "created_at",
1880
+ "updated_at"
1881
+ ]
1882
+ },
1831
1883
  "CreateProjectBody": {
1832
1884
  "type": "object",
1833
1885
  "properties": {
@@ -2546,9 +2598,112 @@
2546
2598
  }
2547
2599
  }
2548
2600
  ]
2601
+ },
2602
+ "include": {
2603
+ "type": "string"
2549
2604
  }
2550
2605
  }
2551
2606
  },
2607
+ "TodoWithRelations": {
2608
+ "type": "object",
2609
+ "properties": {
2610
+ "id": {
2611
+ "type": "string"
2612
+ },
2613
+ "user_id": {
2614
+ "type": "string"
2615
+ },
2616
+ "project_id": {
2617
+ "type": "string",
2618
+ "description": "Project id this todo belongs to. Use /todo/projects/{id} to inspect the project."
2619
+ },
2620
+ "title": {
2621
+ "type": "string"
2622
+ },
2623
+ "description": {
2624
+ "type": "string"
2625
+ },
2626
+ "status": {
2627
+ "type": "string",
2628
+ "enum": [
2629
+ "open",
2630
+ "in_progress",
2631
+ "done",
2632
+ "cancelled"
2633
+ ]
2634
+ },
2635
+ "parent_id": {
2636
+ "type": [
2637
+ "string",
2638
+ "null"
2639
+ ]
2640
+ },
2641
+ "child_count": {
2642
+ "type": "integer",
2643
+ "minimum": 0
2644
+ },
2645
+ "version": {
2646
+ "type": "integer",
2647
+ "minimum": 0
2648
+ },
2649
+ "created_at": {
2650
+ "type": "number"
2651
+ },
2652
+ "updated_at": {
2653
+ "type": "number"
2654
+ },
2655
+ "deleted_at": {
2656
+ "type": "number"
2657
+ },
2658
+ "due_at": {
2659
+ "type": "string"
2660
+ },
2661
+ "type_id": {
2662
+ "type": "string"
2663
+ },
2664
+ "custom_fields": {
2665
+ "type": "object",
2666
+ "additionalProperties": {
2667
+ "anyOf": [
2668
+ {
2669
+ "type": "string"
2670
+ },
2671
+ {
2672
+ "type": "array",
2673
+ "items": {
2674
+ "type": "string"
2675
+ }
2676
+ }
2677
+ ]
2678
+ }
2679
+ },
2680
+ "children": {
2681
+ "type": "array",
2682
+ "items": {
2683
+ "$ref": "#/components/schemas/Todo"
2684
+ }
2685
+ },
2686
+ "comments": {
2687
+ "type": "array",
2688
+ "items": {
2689
+ "$ref": "#/components/schemas/Comment"
2690
+ }
2691
+ }
2692
+ },
2693
+ "required": [
2694
+ "id",
2695
+ "user_id",
2696
+ "project_id",
2697
+ "title",
2698
+ "status",
2699
+ "parent_id",
2700
+ "child_count",
2701
+ "version",
2702
+ "created_at",
2703
+ "updated_at",
2704
+ "type_id"
2705
+ ]
2706
+ },
2552
2707
  "ListRecurrenceRulesQuery": {
2553
2708
  "type": "object",
2554
2709
  "properties": {
@@ -2627,6 +2782,19 @@
2627
2782
  "descendants_in_trash_count"
2628
2783
  ]
2629
2784
  },
2785
+ "UpdateCommentBody": {
2786
+ "type": "object",
2787
+ "properties": {
2788
+ "content": {
2789
+ "type": "string",
2790
+ "minLength": 1,
2791
+ "maxLength": 10000
2792
+ }
2793
+ },
2794
+ "required": [
2795
+ "content"
2796
+ ]
2797
+ },
2630
2798
  "UpdateProjectBody": {
2631
2799
  "type": "object",
2632
2800
  "properties": {
@@ -2894,11 +3062,6 @@
2894
3062
  "lang": "bash",
2895
3063
  "label": "wspc CLI",
2896
3064
  "source": "wspc invite accept inv_01KT43YKZ8CX14WS6ENXQ8397E"
2897
- },
2898
- {
2899
- "lang": "typescript",
2900
- "label": "@wspc/client",
2901
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"${EXAMPLE_API_BASE_URL}\" })\nconst org = await auth.acceptInvite(process.env.WSPC_API_KEY!, \"inv_01KT43YKZ8CX14WS6ENXQ8397E\")"
2902
3065
  }
2903
3066
  ],
2904
3067
  "parameters": [
@@ -3290,11 +3453,6 @@
3290
3453
  "lang": "bash",
3291
3454
  "label": "wspc CLI",
3292
3455
  "source": "wspc keys create --label \"openclaw-tokyo\""
3293
- },
3294
- {
3295
- "lang": "typescript",
3296
- "label": "@wspc/client",
3297
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"https://api.wspc.ai\" })\nconst { api_key } = await auth.createKey(process.env.WSPC_API_KEY!, { label: \"Claude\" })"
3298
3456
  }
3299
3457
  ],
3300
3458
  "requestBody": {
@@ -3685,11 +3843,6 @@
3685
3843
  "lang": "bash",
3686
3844
  "label": "wspc CLI",
3687
3845
  "source": "wspc keys ls"
3688
- },
3689
- {
3690
- "lang": "typescript",
3691
- "label": "@wspc/client",
3692
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"https://api.wspc.ai\" })\nconst { keys } = await auth.listKeys(process.env.WSPC_API_KEY!)"
3693
3846
  }
3694
3847
  ],
3695
3848
  "responses": {
@@ -4068,11 +4221,6 @@
4068
4221
  "lang": "bash",
4069
4222
  "label": "wspc CLI",
4070
4223
  "source": "wspc org invite bob@example.com"
4071
- },
4072
- {
4073
- "lang": "typescript",
4074
- "label": "@wspc/client",
4075
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"${EXAMPLE_API_BASE_URL}\" })\nawait auth.createOrgInvite(process.env.WSPC_API_KEY!, \"bob@example.com\")"
4076
4224
  }
4077
4225
  ],
4078
4226
  "requestBody": {
@@ -4459,11 +4607,6 @@
4459
4607
  "lang": "bash",
4460
4608
  "label": "wspc CLI",
4461
4609
  "source": "wspc org invites"
4462
- },
4463
- {
4464
- "lang": "typescript",
4465
- "label": "@wspc/client",
4466
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"${EXAMPLE_API_BASE_URL}\" })\nconst { invites } = await auth.listOrgInvites(process.env.WSPC_API_KEY!)"
4467
4610
  }
4468
4611
  ],
4469
4612
  "responses": {
@@ -4822,11 +4965,6 @@
4822
4965
  "lang": "bash",
4823
4966
  "label": "wspc CLI",
4824
4967
  "source": "# No direct CLI command — OAuth is consumed by third-party clients"
4825
- },
4826
- {
4827
- "lang": "typescript",
4828
- "label": "@wspc/client",
4829
- "source": "// TODO: client method pending\n// Expected shape:\n// const dev = await fetch(\"https://api.wspc.ai/auth/oauth/device\", {\n// method: \"POST\",\n// headers: { \"Content-Type\": \"application/json\" },\n// body: JSON.stringify({ client_id: \"oac_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\" }),\n// }).then(r => r.json())"
4830
4968
  }
4831
4969
  ],
4832
4970
  "requestBody": {
@@ -5070,11 +5208,6 @@
5070
5208
  "lang": "bash",
5071
5209
  "label": "wspc CLI",
5072
5210
  "source": "wspc org show"
5073
- },
5074
- {
5075
- "lang": "typescript",
5076
- "label": "@wspc/client",
5077
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"https://api.wspc.ai\" })\nconst org = await auth.getOrg(process.env.WSPC_API_KEY!)"
5078
5211
  }
5079
5212
  ],
5080
5213
  "responses": {
@@ -5457,11 +5590,6 @@
5457
5590
  "lang": "bash",
5458
5591
  "label": "wspc CLI",
5459
5592
  "source": "wspc org rename \"New Name\""
5460
- },
5461
- {
5462
- "lang": "typescript",
5463
- "label": "@wspc/client",
5464
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"https://api.wspc.ai\" })\nconst org = await auth.updateOrg(process.env.WSPC_API_KEY!, \"New Name\")"
5465
5593
  }
5466
5594
  ],
5467
5595
  "requestBody": {
@@ -5839,11 +5967,6 @@
5839
5967
  "lang": "bash",
5840
5968
  "label": "wspc CLI",
5841
5969
  "source": "wspc invite show inv_01KT43YKZ8CX14WS6ENXQ8397E"
5842
- },
5843
- {
5844
- "lang": "typescript",
5845
- "label": "@wspc/client",
5846
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"${EXAMPLE_API_BASE_URL}\" })\nconst invite = await auth.getMyInvite(process.env.WSPC_API_KEY!, \"inv_01KT43YKZ8CX14WS6ENXQ8397E\")"
5847
5970
  }
5848
5971
  ],
5849
5972
  "parameters": [
@@ -6238,11 +6361,6 @@
6238
6361
  "lang": "bash",
6239
6362
  "label": "wspc CLI",
6240
6363
  "source": "wspc verify # checks the active env API key\nwspc verify --json # JSON output"
6241
- },
6242
- {
6243
- "lang": "typescript",
6244
- "label": "@wspc/client",
6245
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"https://api.wspc.ai\" })\nconst me = await auth.getMe(process.env.WSPC_API_KEY!)"
6246
6364
  }
6247
6365
  ],
6248
6366
  "responses": {
@@ -6641,11 +6759,6 @@
6641
6759
  "lang": "bash",
6642
6760
  "label": "wspc CLI",
6643
6761
  "source": "wspc invites"
6644
- },
6645
- {
6646
- "lang": "typescript",
6647
- "label": "@wspc/client",
6648
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"${EXAMPLE_API_BASE_URL}\" })\nconst { invites } = await auth.listMyInvites(process.env.WSPC_API_KEY!)"
6649
6762
  }
6650
6763
  ],
6651
6764
  "responses": {
@@ -7025,11 +7138,6 @@
7025
7138
  "lang": "bash",
7026
7139
  "label": "wspc CLI",
7027
7140
  "source": "wspc org members ls"
7028
- },
7029
- {
7030
- "lang": "typescript",
7031
- "label": "@wspc/client",
7032
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"https://api.wspc.ai\" })\nconst { members } = await auth.listOrgMembers(process.env.WSPC_API_KEY!)"
7033
7141
  }
7034
7142
  ],
7035
7143
  "parameters": [
@@ -7413,11 +7521,6 @@
7413
7521
  "lang": "bash",
7414
7522
  "label": "wspc CLI",
7415
7523
  "source": "# No direct CLI command — OAuth is consumed by third-party clients"
7416
- },
7417
- {
7418
- "lang": "typescript",
7419
- "label": "@wspc/client",
7420
- "source": "// TODO: client method pending\n// Expected shape:\n// const meta = await fetch(\"https://api.wspc.ai/.well-known/oauth-authorization-server\").then(r => r.json())"
7421
7524
  }
7422
7525
  ],
7423
7526
  "responses": {
@@ -7802,11 +7905,6 @@
7802
7905
  "lang": "shell",
7803
7906
  "label": "curl",
7804
7907
  "source": "curl https://api.wspc.ai/.well-known/openid-configuration"
7805
- },
7806
- {
7807
- "lang": "typescript",
7808
- "label": "@wspc/client",
7809
- "source": "// TODO: client method pending\n// Expected shape (identical to /.well-known/oauth-authorization-server):\n// const meta = await fetch(\"https://api.wspc.ai/.well-known/openid-configuration\").then(r => r.json())"
7810
7908
  }
7811
7909
  ],
7812
7910
  "responses": {
@@ -8165,11 +8263,6 @@
8165
8263
  "lang": "bash",
8166
8264
  "label": "wspc CLI",
8167
8265
  "source": "# No direct CLI command — OAuth is consumed by third-party clients"
8168
- },
8169
- {
8170
- "lang": "typescript",
8171
- "label": "@wspc/client",
8172
- "source": "// TODO: client method pending\n// Expected shape:\n// const reg = await fetch(\"https://api.wspc.ai/auth/oauth/register\", {\n// method: \"POST\",\n// headers: { \"Content-Type\": \"application/json\" },\n// body: JSON.stringify({ client_name: \"Acme MCP Agent\", redirect_uris: [\"http://localhost:3000/callback\"] }),\n// }).then(r => r.json())"
8173
8266
  }
8174
8267
  ],
8175
8268
  "requestBody": {
@@ -8407,11 +8500,6 @@
8407
8500
  "lang": "bash",
8408
8501
  "label": "wspc CLI",
8409
8502
  "source": "wspc invite reject inv_01KT43YKZ8CX14WS6ENXQ8397E"
8410
- },
8411
- {
8412
- "lang": "typescript",
8413
- "label": "@wspc/client",
8414
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"${EXAMPLE_API_BASE_URL}\" })\nawait auth.rejectInvite(process.env.WSPC_API_KEY!, \"inv_01KT43YKZ8CX14WS6ENXQ8397E\")"
8415
8503
  }
8416
8504
  ],
8417
8505
  "parameters": [
@@ -8774,11 +8862,6 @@
8774
8862
  "lang": "shell",
8775
8863
  "label": "curl",
8776
8864
  "source": "curl -X DELETE https://api.wspc.ai/auth/me/org/members/usr_member \\\n -H \"Authorization: Bearer $WSPC_API_KEY\""
8777
- },
8778
- {
8779
- "lang": "typescript",
8780
- "label": "@wspc/client",
8781
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"https://api.wspc.ai\" })\nawait auth.removeOrgMember(process.env.WSPC_API_KEY!, \"usr_member\")"
8782
8865
  }
8783
8866
  ],
8784
8867
  "parameters": [
@@ -9143,11 +9226,6 @@
9143
9226
  "lang": "bash",
9144
9227
  "label": "wspc CLI",
9145
9228
  "source": "wspc login # prompts for email, then for the magic code"
9146
- },
9147
- {
9148
- "lang": "typescript",
9149
- "label": "@wspc/client",
9150
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"https://api.wspc.ai\" })\nawait auth.requestCode(\"alice@example.com\")"
9151
9229
  }
9152
9230
  ],
9153
9231
  "requestBody": {
@@ -9542,11 +9620,6 @@
9542
9620
  "lang": "bash",
9543
9621
  "label": "wspc CLI",
9544
9622
  "source": "wspc keys rm key_abcd1234efgh5678"
9545
- },
9546
- {
9547
- "lang": "typescript",
9548
- "label": "@wspc/client",
9549
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"https://api.wspc.ai\" })\nawait auth.revokeKey(process.env.WSPC_API_KEY!, \"key_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\")"
9550
9623
  }
9551
9624
  ],
9552
9625
  "parameters": [
@@ -9925,11 +9998,6 @@
9925
9998
  "lang": "bash",
9926
9999
  "label": "wspc CLI",
9927
10000
  "source": "wspc keys edit key_01HW3K4N9V5G6Z8C2Q7B1Y0M3F --label \"New Label\""
9928
- },
9929
- {
9930
- "lang": "typescript",
9931
- "label": "@wspc/client",
9932
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"https://api.wspc.ai\" })\nawait auth.updateApiKeyLabel(process.env.WSPC_API_KEY!, \"key_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\", \"New Label\")"
9933
10001
  }
9934
10002
  ],
9935
10003
  "parameters": [
@@ -10310,11 +10378,6 @@
10310
10378
  "lang": "bash",
10311
10379
  "label": "wspc CLI",
10312
10380
  "source": "# No direct CLI command — OAuth is consumed by third-party clients"
10313
- },
10314
- {
10315
- "lang": "typescript",
10316
- "label": "@wspc/client",
10317
- "source": "// TODO: client method pending\n// Expected shape:\n// await fetch(\"https://api.wspc.ai/auth/oauth/revoke\", {\n// method: \"POST\",\n// headers: { \"Content-Type\": \"application/json\" },\n// body: JSON.stringify({ token: \"rt_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\", token_type_hint: \"refresh_token\" }),\n// })"
10318
10381
  }
10319
10382
  ],
10320
10383
  "requestBody": {
@@ -10535,11 +10598,6 @@
10535
10598
  "lang": "bash",
10536
10599
  "label": "wspc CLI",
10537
10600
  "source": "wspc org invite revoke inv_01KT43YKZ8CX14WS6ENXQ8397E"
10538
- },
10539
- {
10540
- "lang": "typescript",
10541
- "label": "@wspc/client",
10542
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"${EXAMPLE_API_BASE_URL}\" })\nawait auth.revokeOrgInvite(process.env.WSPC_API_KEY!, \"inv_01KT43YKZ8CX14WS6ENXQ8397E\")"
10543
10601
  }
10544
10602
  ],
10545
10603
  "parameters": [
@@ -10903,11 +10961,6 @@
10903
10961
  "lang": "bash",
10904
10962
  "label": "wspc CLI",
10905
10963
  "source": "# No direct CLI command — OAuth is consumed by third-party clients"
10906
- },
10907
- {
10908
- "lang": "typescript",
10909
- "label": "@wspc/client",
10910
- "source": "// TODO: client method pending\n// Expected shape:\n// const tok = await fetch(\"https://api.wspc.ai/auth/oauth/token\", {\n// method: \"POST\",\n// headers: { \"Content-Type\": \"application/json\" },\n// body: JSON.stringify({\n// grant_type: \"refresh_token\",\n// refresh_token: \"rt_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\",\n// client_id: \"oac_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\",\n// }),\n// }).then(r => r.json())"
10911
10964
  }
10912
10965
  ],
10913
10966
  "requestBody": {
@@ -11137,11 +11190,6 @@
11137
11190
  "lang": "bash",
11138
11191
  "label": "wspc CLI",
11139
11192
  "source": "wspc login # prompts for the code after request-code"
11140
- },
11141
- {
11142
- "lang": "typescript",
11143
- "label": "@wspc/client",
11144
- "source": "import { AuthClient } from \"@wspc/client\"\nconst auth = new AuthClient({ baseUrl: \"https://api.wspc.ai\" })\nconst { api_key } = await auth.verifyCode(\"alice@example.com\", \"123456\")"
11145
11193
  }
11146
11194
  ],
11147
11195
  "requestBody": {
@@ -11583,11 +11631,6 @@
11583
11631
  "lang": "bash",
11584
11632
  "label": "wspc CLI",
11585
11633
  "source": "wspc event add \"Lunch with Alice\" \\\n --start \"tomorrow 12:30pm\" --end \"tomorrow 1:30pm\" \\\n --location \"Taipei HQ\" \\\n --attendee \"Alice <alice@example.com>\""
11586
- },
11587
- {
11588
- "lang": "typescript",
11589
- "label": "@wspc/client",
11590
- "source": "import { CalendarClient } from \"@wspc/client\"\nconst calendar = new CalendarClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait calendar.create({\n title: \"Lunch with Alice\",\n start: \"2026-06-01T12:30:00+08:00\",\n end: \"2026-06-01T13:30:00+08:00\",\n attendees: [{ email: \"alice@example.com\", display_name: \"Alice\" }],\n})"
11591
11634
  }
11592
11635
  ],
11593
11636
  "requestBody": {
@@ -12066,11 +12109,6 @@
12066
12109
  "lang": "bash",
12067
12110
  "label": "wspc CLI",
12068
12111
  "source": "wspc event ls --from \"next Monday\" --to \"next Friday\""
12069
- },
12070
- {
12071
- "lang": "typescript",
12072
- "label": "@wspc/client",
12073
- "source": "import { CalendarClient } from \"@wspc/client\"\nconst calendar = new CalendarClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait calendar.list({ start_from: \"2026-06-01T00:00:00+08:00\", start_to: \"2026-06-30T23:59:59+08:00\" })"
12074
12112
  }
12075
12113
  ],
12076
12114
  "parameters": [
@@ -12591,11 +12629,6 @@
12591
12629
  "lang": "bash",
12592
12630
  "label": "wspc CLI",
12593
12631
  "source": "wspc event rm evt_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
12594
- },
12595
- {
12596
- "lang": "typescript",
12597
- "label": "@wspc/client",
12598
- "source": "import { CalendarClient } from \"@wspc/client\"\nconst calendar = new CalendarClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait calendar.delete(\"evt_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\")"
12599
12632
  }
12600
12633
  ],
12601
12634
  "parameters": [
@@ -13021,11 +13054,6 @@
13021
13054
  "lang": "bash",
13022
13055
  "label": "wspc CLI",
13023
13056
  "source": "wspc event show evt_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
13024
- },
13025
- {
13026
- "lang": "typescript",
13027
- "label": "@wspc/client",
13028
- "source": "import { CalendarClient } from \"@wspc/client\"\nconst calendar = new CalendarClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait calendar.get(\"evt_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\")"
13029
13057
  }
13030
13058
  ],
13031
13059
  "parameters": [
@@ -13476,11 +13504,6 @@
13476
13504
  "lang": "bash",
13477
13505
  "label": "wspc CLI",
13478
13506
  "source": "wspc event set evt_01HW3K4N9V5G6Z8C2Q7B1Y0M3F \\\n --start \"tomorrow 1pm\" --end \"tomorrow 2pm\""
13479
- },
13480
- {
13481
- "lang": "typescript",
13482
- "label": "@wspc/client",
13483
- "source": "import { CalendarClient } from \"@wspc/client\"\nconst calendar = new CalendarClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait calendar.update(\"evt_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\", {\n start: \"2026-06-01T13:00:00+08:00\",\n end: \"2026-06-01T14:00:00+08:00\",\n})"
13484
13507
  }
13485
13508
  ],
13486
13509
  "parameters": [
@@ -13937,11 +13960,6 @@
13937
13960
  "lang": "bash",
13938
13961
  "label": "wspc CLI",
13939
13962
  "source": "wspc event ics evt_01HW3K4N9V5G6Z8C2Q7B1Y0M3F > event.ics"
13940
- },
13941
- {
13942
- "lang": "typescript",
13943
- "label": "@wspc/client",
13944
- "source": "import { CalendarClient } from \"@wspc/client\"\nconst calendar = new CalendarClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nconst ics = await calendar.getIcs(\"evt_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\")"
13945
13963
  }
13946
13964
  ],
13947
13965
  "parameters": [
@@ -14315,11 +14333,6 @@
14315
14333
  "lang": "shell",
14316
14334
  "label": "curl",
14317
14335
  "source": "curl -X POST https://api.wspc.ai/calendar/events/evt_01HW3K4N9V5G6Z8C2Q7B1Y0M3F/restore \\\n -H \"Authorization: Bearer $WSPC_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{}'"
14318
- },
14319
- {
14320
- "lang": "typescript",
14321
- "label": "@wspc/client",
14322
- "source": "import { CalendarClient } from \"@wspc/client\"\nconst calendar = new CalendarClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait calendar.restore(\"evt_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\")"
14323
14336
  }
14324
14337
  ],
14325
14338
  "parameters": [
@@ -14755,11 +14768,6 @@
14755
14768
  "lang": "bash",
14756
14769
  "label": "wspc CLI",
14757
14770
  "source": "wspc email alias create alice-shop@wspc.app"
14758
- },
14759
- {
14760
- "lang": "typescript",
14761
- "label": "@wspc/client",
14762
- "source": "import { EmailClient } from \"@wspc/client\"\nconst email = new EmailClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait email.aliasCreate({ email: \"alice-shop@wspc.app\" })"
14763
14771
  }
14764
14772
  ],
14765
14773
  "requestBody": {
@@ -15042,11 +15050,6 @@
15042
15050
  "lang": "bash",
15043
15051
  "label": "wspc CLI",
15044
15052
  "source": "wspc email alias ls"
15045
- },
15046
- {
15047
- "lang": "typescript",
15048
- "label": "@wspc/client",
15049
- "source": "import { EmailClient } from \"@wspc/client\"\nconst email = new EmailClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait email.aliasList()"
15050
15053
  }
15051
15054
  ],
15052
15055
  "parameters": [
@@ -15310,11 +15313,6 @@
15310
15313
  "lang": "bash",
15311
15314
  "label": "wspc CLI",
15312
15315
  "source": "wspc email alias rm alice-shop@wspc.app"
15313
- },
15314
- {
15315
- "lang": "typescript",
15316
- "label": "@wspc/client",
15317
- "source": "import { EmailClient } from \"@wspc/client\"\nconst email = new EmailClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait email.aliasDelete(\"alice-shop@wspc.app\")"
15318
15316
  }
15319
15317
  ],
15320
15318
  "parameters": [
@@ -15548,11 +15546,6 @@
15548
15546
  "lang": "bash",
15549
15547
  "label": "wspc CLI",
15550
15548
  "source": "wspc email rm eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3G"
15551
- },
15552
- {
15553
- "lang": "typescript",
15554
- "label": "@wspc/client",
15555
- "source": "import { EmailClient } from \"@wspc/client\"\nconst email = new EmailClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait email.deleteMany([\"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\", \"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3G\"])"
15556
15549
  }
15557
15550
  ],
15558
15551
  "requestBody": {
@@ -15828,11 +15821,6 @@
15828
15821
  "lang": "bash",
15829
15822
  "label": "wspc CLI",
15830
15823
  "source": "wspc email attachment eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F 0 --output invoice.pdf"
15831
- },
15832
- {
15833
- "lang": "typescript",
15834
- "label": "@wspc/client",
15835
- "source": "import { EmailClient } from \"@wspc/client\"\nconst email = new EmailClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nconst { bytes, filename, mime_type } = await email.attachment(\"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\", 0)"
15836
15824
  }
15837
15825
  ],
15838
15826
  "parameters": [
@@ -16093,11 +16081,6 @@
16093
16081
  "lang": "bash",
16094
16082
  "label": "wspc CLI",
16095
16083
  "source": "wspc email show eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
16096
- },
16097
- {
16098
- "lang": "typescript",
16099
- "label": "@wspc/client",
16100
- "source": "import { EmailClient } from \"@wspc/client\"\nconst email = new EmailClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait email.get(\"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\", { include_html: true })"
16101
16084
  }
16102
16085
  ],
16103
16086
  "parameters": [
@@ -16611,11 +16594,6 @@
16611
16594
  "lang": "bash",
16612
16595
  "label": "wspc CLI",
16613
16596
  "source": "wspc email ls --unread --limit 20"
16614
- },
16615
- {
16616
- "lang": "typescript",
16617
- "label": "@wspc/client",
16618
- "source": "import { EmailClient } from \"@wspc/client\"\nconst email = new EmailClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait email.list({ unread_only: true, limit: 20 })"
16619
16597
  }
16620
16598
  ],
16621
16599
  "parameters": [
@@ -17046,11 +17024,6 @@
17046
17024
  "lang": "bash",
17047
17025
  "label": "wspc CLI",
17048
17026
  "source": "wspc email read eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3G"
17049
- },
17050
- {
17051
- "lang": "typescript",
17052
- "label": "@wspc/client",
17053
- "source": "import { EmailClient } from \"@wspc/client\"\nconst email = new EmailClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait email.markRead([\"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\", \"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3G\"])"
17054
17027
  }
17055
17028
  ],
17056
17029
  "requestBody": {
@@ -17338,11 +17311,6 @@
17338
17311
  "lang": "bash",
17339
17312
  "label": "wspc CLI",
17340
17313
  "source": "wspc email unread eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
17341
- },
17342
- {
17343
- "lang": "typescript",
17344
- "label": "@wspc/client",
17345
- "source": "import { EmailClient } from \"@wspc/client\"\nconst email = new EmailClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait email.markUnread([\"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\"])"
17346
17314
  }
17347
17315
  ],
17348
17316
  "requestBody": {
@@ -17613,11 +17581,6 @@
17613
17581
  "lang": "shell",
17614
17582
  "label": "curl",
17615
17583
  "source": "curl -X POST https://api.wspc.ai/email/aliases/alice-shop%40wspc.app/restore \\\n -H \"Authorization: Bearer $WSPC_API_KEY\""
17616
- },
17617
- {
17618
- "lang": "typescript",
17619
- "label": "@wspc/client",
17620
- "source": "import { EmailClient } from \"@wspc/client\"\nconst email = new EmailClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait email.aliasRestore(\"alice-shop@wspc.app\")"
17621
17584
  }
17622
17585
  ],
17623
17586
  "parameters": [
@@ -17819,11 +17782,6 @@
17819
17782
  "lang": "shell",
17820
17783
  "label": "curl",
17821
17784
  "source": "curl -X POST https://api.wspc.ai/email/messages/restore \\\n -H \"Authorization: Bearer $WSPC_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"ids\":[\"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\"]}'"
17822
- },
17823
- {
17824
- "lang": "typescript",
17825
- "label": "@wspc/client",
17826
- "source": "import { EmailClient } from \"@wspc/client\"\nconst email = new EmailClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait email.restoreMany([\"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\"])"
17827
17785
  }
17828
17786
  ],
17829
17787
  "requestBody": {
@@ -18079,7 +18037,7 @@
18079
18037
  "Emails"
18080
18038
  ],
18081
18039
  "summary": "Send an outbound email",
18082
- "description": "### Overview\nSubmits a single outbound email for delivery from one of the caller's active aliases. All details, including attachments (inline base64 blobs or references to existing inbound attachments), are verified and sent using the Cloudflare email service provider.\n\n### When to Use\n- Use this endpoint to send new standalone emails or to reply to threaded inbound messages.\n- Use this in automated agent pipelines (like calendar invite generation or notifications) and CLI email send utilities.\n\n### Constraints\n- Requires a valid Bearer token in the `Authorization` header.\n- **Size Limits**: Individual attachments must not exceed 5 MiB, and the total size of all attachments per send must be 25 MiB or less.\n- **Security**: Up to 10 attachments are allowed. Outbound files with dangerous executable extensions (such as `.exe`, `.bat`, `.com`, `.scr`, `.cmd`, `.jar`, `.js`) are strictly blocked.\n- **Daily Quotas**: Sending is protected by per-user (100 sends/day) and per-alias (50 sends/day) daily quotas. Exceeding them triggers `RATE_LIMITED` or `QUOTA_EXCEEDED` errors.\n- **Idempotency**: A stable `idempotency_key` (1-200 characters) must be supplied. Retrying a send with identical content and the same key returns `idempotent_replay: true` without sending duplicates. Reusing the key with changed content returns 409 `IDEMPOTENCY_KEY_REUSED`.\n\n### Troubleshooting\n- **401 Unauthorized**: Active Bearer token is invalid or has expired.\n- **404 Not Found**: The requested `from_alias_email` does not exist or has been soft-deleted, or the referenced `in_reply_to_email_id` is missing or belongs to a different user.\n- **409 Conflict / IDEMPOTENCY_KEY_REUSED**: An identical `idempotency_key` was reused with modified request payload. Use a fresh unique key.\n- **429 Too Many Requests / RATE_LIMITED**: The per-user rate limit or daily sending quota has been exceeded. Wait for quota reset.\n- **502 Bad Gateway**: The upstream Cloudflare email provider failed or rejected the message. The outbound row is persisted with `status: failed` along with provider-returned logs.",
18040
+ "description": "### Overview\nSubmits a single outbound email for delivery from one of the caller's active aliases. All details, including attachments (inline base64 blobs or references to existing inbound attachments), are verified before sending. Platform-domain aliases use Cloudflare Email Service; verified custom-domain aliases use pete-mail.\n\n### When to Use\n- Use this endpoint to send new standalone emails or to reply to threaded inbound messages.\n- Use this in automated agent pipelines (like calendar invite generation or notifications) and CLI email send utilities.\n\n### Constraints\n- Requires a valid Bearer token in the `Authorization` header.\n- **Size Limits**: Individual attachments must not exceed 5 MiB, and the total size of all attachments per send must be 25 MiB or less.\n- **Security**: Up to 10 attachments are allowed. Outbound files with dangerous executable extensions (such as `.exe`, `.bat`, `.com`, `.scr`, `.cmd`, `.jar`, `.js`) are strictly blocked.\n- **Daily Quotas**: Sending is protected by per-user (100 sends/day) and per-alias (50 sends/day) daily quotas. Exceeding them triggers `RATE_LIMITED` or `QUOTA_EXCEEDED` errors.\n- **Custom Domains**: Platform-domain aliases use Cloudflare Email Service. Verified custom-domain aliases are routed through pete-mail. Custom domains must have `status = verified` and `sending_status = verified` or the send returns `CUSTOM_DOMAIN_NOT_READY`.\n- **Idempotency**: A stable `idempotency_key` (1-200 characters) must be supplied. Retrying a send with identical content and the same key returns `idempotent_replay: true` without sending duplicates. Reusing the key with changed content returns 409 `IDEMPOTENCY_KEY_REUSED`.\n\n### Troubleshooting\n- **401 Unauthorized**: Active Bearer token is invalid or has expired.\n- **404 Not Found**: The requested `from_alias_email` does not exist or has been soft-deleted, or the referenced `in_reply_to_email_id` is missing or belongs to a different user.\n- **409 Conflict / IDEMPOTENCY_KEY_REUSED**: An identical `idempotency_key` was reused with modified request payload. Use a fresh unique key.\n- **409 Conflict / CUSTOM_DOMAIN_NOT_READY**: The sender uses a custom domain that has not completed outbound sending verification.\n- **429 Too Many Requests / RATE_LIMITED**: The per-user rate limit or daily sending quota has been exceeded. Wait for quota reset.\n- **502 Bad Gateway**: The upstream outbound provider failed or rejected the message. The outbound row is persisted with `status: failed` along with provider-returned logs.",
18083
18041
  "security": [
18084
18042
  {
18085
18043
  "bearerAuth": []
@@ -18099,11 +18057,6 @@
18099
18057
  "lang": "bash",
18100
18058
  "label": "wspc CLI",
18101
18059
  "source": "wspc email send \\\n --from alice-shop@wspc.app \\\n --to alice@example.com \\\n --subject \"Welcome to WSPC\" \\\n --text \"Hi Alice — welcome aboard.\" \\\n --attach ./report.pdf \\\n --idempotency-key retry-20260601-001"
18102
- },
18103
- {
18104
- "lang": "typescript",
18105
- "label": "@wspc/client",
18106
- "source": "import { EmailClient } from \"@wspc/client\"\nconst email = new EmailClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait email.send({\n from_alias_email: \"alice-shop@wspc.app\",\n to: [\"alice@example.com\"],\n subject: \"Welcome to WSPC\",\n text: \"Hi Alice — welcome aboard.\",\n idempotency_key: \"retry-20260601-001\",\n})"
18107
18060
  }
18108
18061
  ],
18109
18062
  "requestBody": {
@@ -18342,7 +18295,7 @@
18342
18295
  }
18343
18296
  },
18344
18297
  "409": {
18345
- "description": "An earlier send under this `idempotency_key` had different content. Pick a new key or repeat the original body byte-for-byte.",
18298
+ "description": "Either an earlier send under this `idempotency_key` had different content, or the sender custom domain has not completed outbound sending verification.",
18346
18299
  "content": {
18347
18300
  "application/json": {
18348
18301
  "schema": {
@@ -18514,11 +18467,6 @@
18514
18467
  "lang": "bash",
18515
18468
  "label": "wspc CLI",
18516
18469
  "source": "wspc push config rm telegram"
18517
- },
18518
- {
18519
- "lang": "typescript",
18520
- "label": "@wspc/client",
18521
- "source": "import { PushClient } from \"@wspc/client\"\nconst push = new PushClient({ baseUrl: \"https://push.wspc.app\", apiKey: process.env.WSPC_API_KEY! })\nawait push.configDelete(\"telegram\")"
18522
18470
  }
18523
18471
  ],
18524
18472
  "x-cli": {
@@ -18787,11 +18735,6 @@
18787
18735
  "lang": "bash",
18788
18736
  "label": "wspc CLI",
18789
18737
  "source": "wspc push config set --transport telegram --target-bot @your_agent_bot"
18790
- },
18791
- {
18792
- "lang": "typescript",
18793
- "label": "@wspc/client",
18794
- "source": "import { PushClient } from \"@wspc/client\"\nconst push = new PushClient({ baseUrl: \"https://push.wspc.app\", apiKey: process.env.WSPC_API_KEY! })\nawait push.configSet({ transport: \"telegram\", target_bot_username: \"@your_agent_bot\" })"
18795
18738
  }
18796
18739
  ],
18797
18740
  "x-cli": {
@@ -19103,11 +19046,6 @@
19103
19046
  "lang": "bash",
19104
19047
  "label": "wspc CLI",
19105
19048
  "source": "wspc push config show"
19106
- },
19107
- {
19108
- "lang": "typescript",
19109
- "label": "@wspc/client",
19110
- "source": "import { PushClient } from \"@wspc/client\"\nconst push = new PushClient({ baseUrl: \"https://push.wspc.app\", apiKey: process.env.WSPC_API_KEY! })\nconst { configs } = await push.configList()"
19111
19049
  }
19112
19050
  ],
19113
19051
  "x-cli": {
@@ -19393,11 +19331,6 @@
19393
19331
  "lang": "bash",
19394
19332
  "label": "wspc CLI",
19395
19333
  "source": "wspc push test"
19396
- },
19397
- {
19398
- "lang": "typescript",
19399
- "label": "@wspc/client",
19400
- "source": "import { PushClient } from \"@wspc/client\"\nconst push = new PushClient({ baseUrl: \"https://push.wspc.app\", apiKey: process.env.WSPC_API_KEY! })\nconst result = await push.test(\"telegram\")"
19401
19334
  }
19402
19335
  ],
19403
19336
  "x-cli": {
@@ -19694,36 +19627,35 @@
19694
19627
  }
19695
19628
  }
19696
19629
  },
19697
- "/todo/projects": {
19630
+ "/todo/items/{id}/comments": {
19698
19631
  "post": {
19699
- "operationId": "project_create",
19632
+ "operationId": "todo_comment_create",
19700
19633
  "tags": [
19701
- "Projects"
19634
+ "Comments"
19702
19635
  ],
19703
19636
  "x-cli": {
19704
- "command": "todo project add",
19637
+ "command": "todo comment add",
19705
19638
  "positional": [
19706
- "name"
19639
+ "id",
19640
+ "content"
19707
19641
  ],
19708
19642
  "examples": [
19709
- "wspc todo project add \"Personal\""
19643
+ "wspc todo comment add tod_01HW3K \"Verified on staging\""
19710
19644
  ],
19711
19645
  "display": {
19712
19646
  "shape": "object",
19713
19647
  "format": {
19714
19648
  "id": "id-short",
19715
- "org_id": "id-short",
19716
- "creator_user_id": "id-short",
19717
- "default_todo_type_id": "id-short",
19718
- "name": "truncate",
19649
+ "todo_id": "id-short",
19650
+ "user_id": "id-short",
19719
19651
  "created_at": "relative-time",
19720
19652
  "updated_at": "relative-time",
19721
19653
  "deleted_at": "relative-time"
19722
19654
  }
19723
19655
  }
19724
19656
  },
19725
- "summary": "Create a project",
19726
- "description": "### 🎯 Overview & Purpose\nEstablish a new isolated project workspace.\n\n### 🔍 When to Use\n* Use this to set up a new domain, team project, or separate workspace area to isolate tasks, custom types, and recurrence rules.\n\n### 💡 Key Features & Constraints\n* **Project Partitioning**: Projects act as strict boundaries. Custom todo types and recurrence rules created under this project are strictly confined to it.\n* **Name Uniqueness**: Project names are free-form and do not have to be unique.\n* **Default Type Inheritance**: Omit `default_todo_type_id` to automatically inherit the Default Project's default task type.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if required fields are missing, if name is empty, or if name length constraints are violated.",
19657
+ "summary": "Add a comment to a todo",
19658
+ "description": "### 🎯 Overview & Purpose\nAttach a free-text comment to a todo. Use this to record progress updates, notes, or remarks as a task moves along.\n\n### 💡 Key Features & Constraints\n* **Free text**: Comments are plain text up to 10000 characters; there is no separate \"progress\" vs \"remark\" type.\n* **Authorship**: The author is recorded as the calling user (`user_id`).\n\n### ⚠️ Common Errors & Troubleshooting\n* **`NOT_FOUND` (HTTP 404)**: Thrown if the target todo does not exist or is soft-deleted.\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if content is empty or exceeds 10000 characters.",
19727
19659
  "security": [
19728
19660
  {
19729
19661
  "bearerAuth": []
@@ -19733,37 +19665,38 @@
19733
19665
  {
19734
19666
  "lang": "shell",
19735
19667
  "label": "curl",
19736
- "source": "curl -X POST https://api.wspc.ai/todo/projects -H \"Authorization: Bearer $WSPC_API_KEY\" -H \"Content-Type: application/json\" -d '{\"name\":\"Work\"}'"
19668
+ "source": "curl -X POST https://api.wspc.ai/todo/items/tod_01HW3K/comments -H \"Authorization: Bearer $WSPC_API_KEY\" -H \"Content-Type: application/json\" -d '{\"content\":\"Looks good\"}'"
19737
19669
  },
19738
19670
  {
19739
19671
  "lang": "bash",
19740
19672
  "label": "wspc CLI",
19741
- "source": "wspc project create --name \"Work\""
19742
- },
19673
+ "source": "wspc todo comment add tod_01HW3K \"Looks good\""
19674
+ }
19675
+ ],
19676
+ "parameters": [
19743
19677
  {
19744
- "lang": "typescript",
19745
- "label": "@wspc/client",
19746
- "source": "await todo.projects.create({ name: \"Work\" })"
19678
+ "schema": {
19679
+ "type": "string",
19680
+ "description": "Todo id (`tod_<ULID>`).",
19681
+ "example": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
19682
+ },
19683
+ "required": true,
19684
+ "description": "Todo id (`tod_<ULID>`).",
19685
+ "name": "id",
19686
+ "in": "path"
19747
19687
  }
19748
19688
  ],
19749
19689
  "requestBody": {
19750
19690
  "content": {
19751
19691
  "application/json": {
19752
19692
  "schema": {
19753
- "$ref": "#/components/schemas/CreateProjectBody"
19693
+ "$ref": "#/components/schemas/CreateCommentBody"
19754
19694
  },
19755
19695
  "examples": {
19756
19696
  "minimal": {
19757
- "summary": "Name only",
19758
- "value": {
19759
- "name": "Launch plan"
19760
- }
19761
- },
19762
- "explicitDefaultType": {
19763
- "summary": "Explicit default todo type",
19697
+ "summary": "Plain comment",
19764
19698
  "value": {
19765
- "name": "Launch plan",
19766
- "default_todo_type_id": "typ_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
19699
+ "content": "Looks good"
19767
19700
  }
19768
19701
  }
19769
19702
  }
@@ -19776,18 +19709,17 @@
19776
19709
  "content": {
19777
19710
  "application/json": {
19778
19711
  "schema": {
19779
- "$ref": "#/components/schemas/Project"
19712
+ "$ref": "#/components/schemas/Comment"
19780
19713
  },
19781
19714
  "examples": {
19782
19715
  "happyPath": {
19783
- "summary": "Active project",
19716
+ "summary": "Active comment",
19784
19717
  "value": {
19785
- "id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
19718
+ "id": "tdc_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
19719
+ "todo_id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
19720
+ "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
19786
19721
  "org_id": "org_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
19787
- "creator_user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
19788
- "name": "Launch plan",
19789
- "default_todo_type_id": "typ_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
19790
- "version": 1,
19722
+ "content": "Verified on staging, moving on.",
19791
19723
  "created_at": 1748736000000,
19792
19724
  "updated_at": 1748736000000
19793
19725
  }
@@ -20122,32 +20054,32 @@
20122
20054
  }
20123
20055
  },
20124
20056
  "get": {
20125
- "operationId": "project_list",
20057
+ "operationId": "todo_comment_list",
20126
20058
  "tags": [
20127
- "Projects"
20059
+ "Comments"
20128
20060
  ],
20129
20061
  "x-cli": {
20130
- "command": "todo project ls",
20062
+ "command": "todo comment ls",
20131
20063
  "examples": [
20132
- "wspc todo project ls"
20064
+ "wspc todo comment ls tod_01HW3K"
20133
20065
  ],
20134
20066
  "display": {
20135
20067
  "shape": "list",
20136
20068
  "columns": [
20137
20069
  "id",
20138
- "name",
20139
- "default_todo_type_id"
20070
+ "content",
20071
+ "created_at"
20140
20072
  ],
20141
20073
  "format": {
20142
20074
  "id": "id-short",
20143
- "name": "truncate",
20144
- "default_todo_type_id": "id-short"
20075
+ "content": "truncate",
20076
+ "created_at": "relative-time"
20145
20077
  },
20146
- "emptyMessage": "no projects"
20078
+ "emptyMessage": "no comments"
20147
20079
  }
20148
20080
  },
20149
- "summary": "List projects",
20150
- "description": "### 🎯 Overview & Purpose\nList all project workspaces available to the authenticated organization or user.\n\n### 🔍 When to Use\n* Use this to populate project switcher dropdown menus, load side navigation views, or find valid project IDs before listing other scoped resources.\n\n### 💡 Key Features & Constraints\n* **Archived Visibility**: Soft-deleted projects are omitted from default listings. Pass `include_deleted=true` to include them for auditing or recovery dashboards.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`AUTH_REQUIRED` (HTTP 401)**: Thrown if the caller is not authenticated.",
20081
+ "summary": "List comments on a todo",
20082
+ "description": "### 🎯 Overview & Purpose\nList the comments attached to a todo, oldest-first by default.\n\n### 💡 Key Features & Constraints\n* **Ordering**: Defaults to chronological (`asc`). Pass `order=desc` for newest-first.\n* **Soft-deleted**: Hidden by default; pass `include_deleted=true` to include them.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`NOT_FOUND` (HTTP 404)**: Thrown if the target todo does not exist or is soft-deleted.",
20151
20083
  "security": [
20152
20084
  {
20153
20085
  "bearerAuth": []
@@ -20157,28 +20089,43 @@
20157
20089
  {
20158
20090
  "lang": "shell",
20159
20091
  "label": "curl",
20160
- "source": "curl https://api.wspc.ai/todo/projects -H \"Authorization: Bearer $WSPC_API_KEY\""
20092
+ "source": "curl https://api.wspc.ai/todo/items/tod_01HW3K/comments -H \"Authorization: Bearer $WSPC_API_KEY\""
20161
20093
  },
20162
20094
  {
20163
20095
  "lang": "bash",
20164
20096
  "label": "wspc CLI",
20165
- "source": "wspc project ls"
20166
- },
20167
- {
20168
- "lang": "typescript",
20169
- "label": "@wspc/client",
20170
- "source": "await todo.projects.list()"
20097
+ "source": "wspc todo comment ls tod_01HW3K"
20171
20098
  }
20172
20099
  ],
20173
20100
  "parameters": [
20174
20101
  {
20175
20102
  "schema": {
20176
20103
  "type": "string",
20177
- "description": "Set to `true` to include soft-deleted projects in the response.",
20178
- "example": "true"
20104
+ "description": "Todo id (`tod_<ULID>`).",
20105
+ "example": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
20106
+ },
20107
+ "required": true,
20108
+ "description": "Todo id (`tod_<ULID>`).",
20109
+ "name": "id",
20110
+ "in": "path"
20111
+ },
20112
+ {
20113
+ "schema": {
20114
+ "type": "string",
20115
+ "enum": [
20116
+ "asc",
20117
+ "desc"
20118
+ ]
20119
+ },
20120
+ "required": false,
20121
+ "name": "order",
20122
+ "in": "query"
20123
+ },
20124
+ {
20125
+ "schema": {
20126
+ "type": "string"
20179
20127
  },
20180
20128
  "required": false,
20181
- "description": "Set to `true` to include soft-deleted projects in the response.",
20182
20129
  "name": "include_deleted",
20183
20130
  "in": "query"
20184
20131
  }
@@ -20191,59 +20138,30 @@
20191
20138
  "schema": {
20192
20139
  "type": "object",
20193
20140
  "properties": {
20194
- "projects": {
20141
+ "comments": {
20195
20142
  "type": "array",
20196
20143
  "items": {
20197
- "$ref": "#/components/schemas/Project"
20144
+ "$ref": "#/components/schemas/Comment"
20198
20145
  }
20199
20146
  }
20200
20147
  },
20201
20148
  "required": [
20202
- "projects"
20149
+ "comments"
20203
20150
  ]
20204
20151
  },
20205
20152
  "examples": {
20206
- "activeProjects": {
20207
- "summary": "Active projects",
20208
- "value": {
20209
- "projects": [
20210
- {
20211
- "id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20212
- "org_id": "org_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20213
- "creator_user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20214
- "name": "Launch plan",
20215
- "default_todo_type_id": "typ_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20216
- "version": 1,
20217
- "created_at": 1748736000000,
20218
- "updated_at": 1748736000000
20219
- }
20220
- ]
20221
- }
20222
- },
20223
- "includeDeleted": {
20224
- "summary": "Including soft-deleted projects",
20153
+ "activeComments": {
20154
+ "summary": "Comments",
20225
20155
  "value": {
20226
- "projects": [
20156
+ "comments": [
20227
20157
  {
20228
- "id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20158
+ "id": "tdc_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20159
+ "todo_id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20160
+ "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20229
20161
  "org_id": "org_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20230
- "creator_user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20231
- "name": "Launch plan",
20232
- "default_todo_type_id": "typ_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20233
- "version": 1,
20162
+ "content": "Verified on staging, moving on.",
20234
20163
  "created_at": 1748736000000,
20235
20164
  "updated_at": 1748736000000
20236
- },
20237
- {
20238
- "id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20239
- "org_id": "org_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20240
- "creator_user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20241
- "name": "Launch plan",
20242
- "default_todo_type_id": "typ_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20243
- "version": 2,
20244
- "created_at": 1748736000000,
20245
- "updated_at": 1748739600000,
20246
- "deleted_at": 1748739600000
20247
20165
  }
20248
20166
  ]
20249
20167
  }
@@ -20578,18 +20496,36 @@
20578
20496
  }
20579
20497
  }
20580
20498
  },
20581
- "/todo/recurrence-rules": {
20499
+ "/todo/projects": {
20582
20500
  "post": {
20583
- "operationId": "recurrence_rule_create",
20501
+ "operationId": "project_create",
20584
20502
  "tags": [
20585
- "RecurrenceRules"
20503
+ "Projects"
20586
20504
  ],
20587
20505
  "x-cli": {
20588
- "command": "_internal",
20589
- "hidden": true
20506
+ "command": "todo project add",
20507
+ "positional": [
20508
+ "name"
20509
+ ],
20510
+ "examples": [
20511
+ "wspc todo project add \"Personal\""
20512
+ ],
20513
+ "display": {
20514
+ "shape": "object",
20515
+ "format": {
20516
+ "id": "id-short",
20517
+ "org_id": "id-short",
20518
+ "creator_user_id": "id-short",
20519
+ "default_todo_type_id": "id-short",
20520
+ "name": "truncate",
20521
+ "created_at": "relative-time",
20522
+ "updated_at": "relative-time",
20523
+ "deleted_at": "relative-time"
20524
+ }
20525
+ }
20590
20526
  },
20591
- "summary": "Create a recurring todo rule",
20592
- "description": "### 🎯 Overview & Purpose\nCreate a recurrence rule that materializes upcoming todo instances on a repeating schedule.\n\n### 🔍 When to Use\n* Use this to set up recurring work like a weekly Standup, monthly reporting, or cyclical maintenance. The server automatically materializes upcoming todo instances on a 14-day rolling horizon.\n\n### 💡 Key Features & Constraints\n* **RFC-5545 Conformity**: The `rrule` parameter must be a valid RFC-5545 schedule string (e.g., `FREQ=WEEKLY;BYDAY=MO`) and must **not** include the `DTSTART` or `TZID` directive.\n* **Anchor Date**: `dtstart` specifies the local calendar starting date (`YYYY-MM-DD`) where the schedule rule is anchored.\n* **Nesting Constraints**: Recurrence rules can only be bound to root-level tasks. Child tasks (subtasks) cannot have recurrence rules. Setting a child task as a parent will trigger `PARENT_IS_CHILD`.\n* **Instance Independence**: Once materialized, each todo instance is fully independent with its own `status` and `due_at`.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`RRULE_INVALID` (HTTP 400)**: Thrown if the `rrule` schedule string is broken or contains illegal `DTSTART` directives.\n* **`PARENT_IS_CHILD` (HTTP 400)**: Thrown if the specified `parent_id` points to a child task.\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if date format is invalid or required fields are missing.",
20527
+ "summary": "Create a project",
20528
+ "description": "### 🎯 Overview & Purpose\nEstablish a new isolated project workspace.\n\n### 🔍 When to Use\n* Use this to set up a new domain, team project, or separate workspace area to isolate tasks, custom types, and recurrence rules.\n\n### 💡 Key Features & Constraints\n* **Project Partitioning**: Projects act as strict boundaries. Custom todo types and recurrence rules created under this project are strictly confined to it.\n* **Name Uniqueness**: Project names are free-form and do not have to be unique.\n* **Default Type Inheritance**: Omit `default_todo_type_id` to automatically inherit the Default Project's default task type.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if required fields are missing, if name is empty, or if name length constraints are violated.",
20593
20529
  "security": [
20594
20530
  {
20595
20531
  "bearerAuth": []
@@ -20599,44 +20535,32 @@
20599
20535
  {
20600
20536
  "lang": "shell",
20601
20537
  "label": "curl",
20602
- "source": "curl -X POST https://api.wspc.ai/todo/recurrence-rules \\\n -H \"Authorization: Bearer $WSPC_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"title\":\"Draft weekly review\",\"rrule\":\"FREQ=WEEKLY;BYDAY=MO\",\"dtstart\":\"2026-05-18\",\"project_id\":\"prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\"}'"
20538
+ "source": "curl -X POST https://api.wspc.ai/todo/projects -H \"Authorization: Bearer $WSPC_API_KEY\" -H \"Content-Type: application/json\" -d '{\"name\":\"Work\"}'"
20603
20539
  },
20604
20540
  {
20605
20541
  "lang": "bash",
20606
20542
  "label": "wspc CLI",
20607
- "source": "wspc todo rrule add \"Draft weekly review\" --rrule \"FREQ=WEEKLY;BYDAY=MO\" --dtstart 2026-05-18 --project prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
20608
- },
20609
- {
20610
- "lang": "typescript",
20611
- "label": "@wspc/client",
20612
- "source": "import { TodoClient } from \"@wspc/client\"\nconst todo = new TodoClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait todo.createRule({ title: \"Draft weekly review\", rrule: \"FREQ=WEEKLY;BYDAY=MO\", dtstart: \"2026-05-18\", project_id: \"prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\" })"
20543
+ "source": "wspc project create --name \"Work\""
20613
20544
  }
20614
20545
  ],
20615
20546
  "requestBody": {
20616
20547
  "content": {
20617
20548
  "application/json": {
20618
20549
  "schema": {
20619
- "$ref": "#/components/schemas/CreateRecurrenceRuleBody"
20550
+ "$ref": "#/components/schemas/CreateProjectBody"
20620
20551
  },
20621
20552
  "examples": {
20622
20553
  "minimal": {
20623
- "summary": "Weekly recurrence anchored on a Monday",
20554
+ "summary": "Name only",
20624
20555
  "value": {
20625
- "rrule": "FREQ=WEEKLY;BYDAY=MO",
20626
- "dtstart": "2026-05-18",
20627
- "title": "Draft weekly review",
20628
- "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
20556
+ "name": "Launch plan"
20629
20557
  }
20630
20558
  },
20631
- "full": {
20632
- "summary": "Weekly recurrence with description + parent",
20559
+ "explicitDefaultType": {
20560
+ "summary": "Explicit default todo type",
20633
20561
  "value": {
20634
- "rrule": "FREQ=WEEKLY;BYDAY=MO",
20635
- "dtstart": "2026-05-18",
20636
- "title": "Draft weekly review",
20637
- "description": "See PRD for context",
20638
- "parent_id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20639
- "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
20562
+ "name": "Launch plan",
20563
+ "default_todo_type_id": "typ_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
20640
20564
  }
20641
20565
  }
20642
20566
  }
@@ -20645,28 +20569,24 @@
20645
20569
  },
20646
20570
  "responses": {
20647
20571
  "201": {
20648
- "description": "The rule was created. `materialized_instance_count` reports how many todo instances were materialized immediately within the 14-day horizon.",
20572
+ "description": "Created",
20649
20573
  "content": {
20650
20574
  "application/json": {
20651
20575
  "schema": {
20652
- "$ref": "#/components/schemas/CreateRecurrenceRuleResponse"
20576
+ "$ref": "#/components/schemas/Project"
20653
20577
  },
20654
20578
  "examples": {
20655
20579
  "happyPath": {
20656
- "summary": "Weekly rule with 2 instances materialized in the 14-day window",
20580
+ "summary": "Active project",
20657
20581
  "value": {
20658
- "rule": {
20659
- "id": "tdr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20660
- "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20661
- "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20662
- "rrule": "FREQ=WEEKLY;BYDAY=MO",
20663
- "dtstart": "2026-05-18",
20664
- "version": 1,
20665
- "created_at": 1748736000000,
20666
- "updated_at": 1748736000000
20667
- },
20668
- "template_todo_id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20669
- "materialized_instance_count": 2
20582
+ "id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20583
+ "org_id": "org_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20584
+ "creator_user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20585
+ "name": "Launch plan",
20586
+ "default_todo_type_id": "typ_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
20587
+ "version": 1,
20588
+ "created_at": 1748736000000,
20589
+ "updated_at": 1748736000000
20670
20590
  }
20671
20591
  }
20672
20592
  }
@@ -20999,31 +20919,32 @@
20999
20919
  }
21000
20920
  },
21001
20921
  "get": {
21002
- "operationId": "recurrence_rule_list",
20922
+ "operationId": "project_list",
21003
20923
  "tags": [
21004
- "RecurrenceRules"
20924
+ "Projects"
21005
20925
  ],
21006
20926
  "x-cli": {
21007
- "command": "todo rule ls",
20927
+ "command": "todo project ls",
21008
20928
  "examples": [
21009
- "wspc todo rule ls"
20929
+ "wspc todo project ls"
21010
20930
  ],
21011
20931
  "display": {
21012
20932
  "shape": "list",
21013
20933
  "columns": [
21014
20934
  "id",
21015
- "rrule",
21016
- "dtstart"
20935
+ "name",
20936
+ "default_todo_type_id"
21017
20937
  ],
21018
20938
  "format": {
21019
20939
  "id": "id-short",
21020
- "rrule": "truncate"
20940
+ "name": "truncate",
20941
+ "default_todo_type_id": "id-short"
21021
20942
  },
21022
- "emptyMessage": "no recurrence rules"
20943
+ "emptyMessage": "no projects"
21023
20944
  }
21024
20945
  },
21025
- "summary": "List recurring todo rules",
21026
- "description": "### 🎯 Overview & Purpose\nReturn all active recurrence rules within a specific project owned by the caller.\n\n### 🔍 When to Use\n* Use this to render rule management panels, list scheduled automation templates, or inspect active rules.\n\n### 💡 Key Features & Constraints\n* **Project Scope**: The `project_id` query parameter is strictly required.\n* **Exclusion**: Soft-deleted/archived rules are excluded from the response by default.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if `project_id` query filter is omitted.",
20946
+ "summary": "List projects",
20947
+ "description": "### 🎯 Overview & Purpose\nList all project workspaces available to the authenticated organization or user.\n\n### 🔍 When to Use\n* Use this to populate project switcher dropdown menus, load side navigation views, or find valid project IDs before listing other scoped resources.\n\n### 💡 Key Features & Constraints\n* **Archived Visibility**: Soft-deleted projects are omitted from default listings. Pass `include_deleted=true` to include them for auditing or recovery dashboards.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`AUTH_REQUIRED` (HTTP 401)**: Thrown if the caller is not authenticated.",
21027
20948
  "security": [
21028
20949
  {
21029
20950
  "bearerAuth": []
@@ -21033,59 +20954,57 @@
21033
20954
  {
21034
20955
  "lang": "shell",
21035
20956
  "label": "curl",
21036
- "source": "curl https://api.wspc.ai/todo/recurrence-rules \\\n -H \"Authorization: Bearer $WSPC_API_KEY\""
20957
+ "source": "curl https://api.wspc.ai/todo/projects -H \"Authorization: Bearer $WSPC_API_KEY\""
21037
20958
  },
21038
20959
  {
21039
20960
  "lang": "bash",
21040
20961
  "label": "wspc CLI",
21041
- "source": "wspc todo rrule ls"
21042
- },
21043
- {
21044
- "lang": "typescript",
21045
- "label": "@wspc/client",
21046
- "source": "import { TodoClient } from \"@wspc/client\"\nconst todo = new TodoClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait todo.listRules()"
20962
+ "source": "wspc project ls"
21047
20963
  }
21048
20964
  ],
21049
20965
  "parameters": [
21050
20966
  {
21051
20967
  "schema": {
21052
20968
  "type": "string",
21053
- "minLength": 1,
21054
- "description": "Project id filter. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND."
21055
- },
21056
- "required": true,
21057
- "description": "Project id filter. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.",
21058
- "name": "project_id",
21059
- "in": "query"
21060
- },
21061
- {
21062
- "schema": {
21063
- "type": "string"
20969
+ "description": "Set to `true` to include soft-deleted projects in the response.",
20970
+ "example": "true"
21064
20971
  },
21065
20972
  "required": false,
21066
- "name": "user_id",
20973
+ "description": "Set to `true` to include soft-deleted projects in the response.",
20974
+ "name": "include_deleted",
21067
20975
  "in": "query"
21068
20976
  }
21069
20977
  ],
21070
20978
  "responses": {
21071
20979
  "200": {
21072
- "description": "Active recurrence rules for the caller. Empty `rules` array when none are configured.",
20980
+ "description": "List",
21073
20981
  "content": {
21074
20982
  "application/json": {
21075
20983
  "schema": {
21076
- "$ref": "#/components/schemas/ListRecurrenceRulesResponse"
21077
- },
21078
- "examples": {
21079
- "happyPath": {
21080
- "summary": "Single weekly rule configured",
21081
- "value": {
21082
- "rules": [
21083
- {
21084
- "id": "tdr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21085
- "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21086
- "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21087
- "rrule": "FREQ=WEEKLY;BYDAY=MO",
21088
- "dtstart": "2026-05-18",
20984
+ "type": "object",
20985
+ "properties": {
20986
+ "projects": {
20987
+ "type": "array",
20988
+ "items": {
20989
+ "$ref": "#/components/schemas/Project"
20990
+ }
20991
+ }
20992
+ },
20993
+ "required": [
20994
+ "projects"
20995
+ ]
20996
+ },
20997
+ "examples": {
20998
+ "activeProjects": {
20999
+ "summary": "Active projects",
21000
+ "value": {
21001
+ "projects": [
21002
+ {
21003
+ "id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21004
+ "org_id": "org_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21005
+ "creator_user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21006
+ "name": "Launch plan",
21007
+ "default_todo_type_id": "typ_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21089
21008
  "version": 1,
21090
21009
  "created_at": 1748736000000,
21091
21010
  "updated_at": 1748736000000
@@ -21093,10 +21012,32 @@
21093
21012
  ]
21094
21013
  }
21095
21014
  },
21096
- "empty": {
21097
- "summary": "No recurring rules",
21015
+ "includeDeleted": {
21016
+ "summary": "Including soft-deleted projects",
21098
21017
  "value": {
21099
- "rules": []
21018
+ "projects": [
21019
+ {
21020
+ "id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21021
+ "org_id": "org_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21022
+ "creator_user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21023
+ "name": "Launch plan",
21024
+ "default_todo_type_id": "typ_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21025
+ "version": 1,
21026
+ "created_at": 1748736000000,
21027
+ "updated_at": 1748736000000
21028
+ },
21029
+ {
21030
+ "id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21031
+ "org_id": "org_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21032
+ "creator_user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21033
+ "name": "Launch plan",
21034
+ "default_todo_type_id": "typ_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21035
+ "version": 2,
21036
+ "created_at": 1748736000000,
21037
+ "updated_at": 1748739600000,
21038
+ "deleted_at": 1748739600000
21039
+ }
21040
+ ]
21100
21041
  }
21101
21042
  }
21102
21043
  }
@@ -21429,44 +21370,18 @@
21429
21370
  }
21430
21371
  }
21431
21372
  },
21432
- "/todo/items": {
21373
+ "/todo/recurrence-rules": {
21433
21374
  "post": {
21434
- "operationId": "todo_create",
21375
+ "operationId": "recurrence_rule_create",
21435
21376
  "tags": [
21436
- "Todos"
21377
+ "RecurrenceRules"
21437
21378
  ],
21438
21379
  "x-cli": {
21439
- "command": "todo add",
21440
- "positional": [
21441
- "title"
21442
- ],
21443
- "aliases": {
21444
- "project": "p"
21445
- },
21446
- "examples": [
21447
- "wspc todo add \"Buy milk\"",
21448
- "wspc todo add \"Buy milk\" --project prj_xxx"
21449
- ],
21450
- "display": {
21451
- "shape": "object",
21452
- "format": {
21453
- "id": "id-short",
21454
- "user_id": "id-short",
21455
- "project_id": "id-short",
21456
- "parent_id": "id-short",
21457
- "type_id": "id-short",
21458
- "title": "truncate",
21459
- "description": "truncate",
21460
- "status": "status-badge",
21461
- "due_at": "relative-time",
21462
- "created_at": "relative-time",
21463
- "updated_at": "relative-time",
21464
- "deleted_at": "relative-time"
21465
- }
21466
- }
21380
+ "command": "_internal",
21381
+ "hidden": true
21467
21382
  },
21468
- "summary": "Create a todo",
21469
- "description": "### 🎯 Overview & Purpose\nCreate a new todo item under a specified project. This can either be a standalone root-level todo or a nested subtask attached to an existing root todo.\n\n### 🔍 When to Use\n* Use this to capture a fresh work item, document an ongoing task, or break a larger root todo into subtasks by creating child todos under it.\n\n### 💡 Key Features & Constraints\n* **One-Level Nesting Limit**: WSPC supports a maximum of one level of task nesting (Root ➔ Child). A root-level todo can have children, but a child todo cannot have further subtasks. Setting a child todo as a parent will fail and trigger a `PARENT_IS_CHILD` error.\n* **Description Handling**: Passing a non-empty string stores the description; passing `\"\"` explicitly stores an empty string. Passing `null` is strictly rejected.\n* **Due Date Format**: Accepts an ISO-8601 date-only format (`YYYY-MM-DD`). Pass `\"\"` or omit the field to skip setting a due date.\n* **Project Binding**: Every todo must belong to a valid active project (`project_id`).\n\n### ⚠️ Common Errors & Troubleshooting\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if required fields are missing, if `due_at` violates the `YYYY-MM-DD` format, or if `title` exceeds 500 characters.\n* **`PARENT_IS_CHILD` (HTTP 400)**: Thrown if the target `parent_id` refers to a todo that is itself already a child todo.\n* **`WOULD_CREATE_CYCLE` (HTTP 400)**: Thrown if `parent_id` points to the todo's own ID.\n* **`NOT_FOUND` (HTTP 404)**: Thrown if the specified `project_id` or `parent_id` does not exist or has been soft-deleted.",
21383
+ "summary": "Create a recurring todo rule",
21384
+ "description": "### 🎯 Overview & Purpose\nCreate a recurrence rule that materializes upcoming todo instances on a repeating schedule.\n\n### 🔍 When to Use\n* Use this to set up recurring work like a weekly Standup, monthly reporting, or cyclical maintenance. The server automatically materializes upcoming todo instances on a 14-day rolling horizon.\n\n### 💡 Key Features & Constraints\n* **RFC-5545 Conformity**: The `rrule` parameter must be a valid RFC-5545 schedule string (e.g., `FREQ=WEEKLY;BYDAY=MO`) and must **not** include the `DTSTART` or `TZID` directive.\n* **Anchor Date**: `dtstart` specifies the local calendar starting date (`YYYY-MM-DD`) where the schedule rule is anchored.\n* **Nesting Constraints**: Recurrence rules can only be bound to root-level tasks. Child tasks (subtasks) cannot have recurrence rules. Setting a child task as a parent will trigger `PARENT_IS_CHILD`.\n* **Instance Independence**: Once materialized, each todo instance is fully independent with its own `status` and `due_at`.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`RRULE_INVALID` (HTTP 400)**: Thrown if the `rrule` schedule string is broken or contains illegal `DTSTART` directives.\n* **`PARENT_IS_CHILD` (HTTP 400)**: Thrown if the specified `parent_id` points to a child task.\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if date format is invalid or required fields are missing.",
21470
21385
  "security": [
21471
21386
  {
21472
21387
  "bearerAuth": []
@@ -21476,40 +21391,39 @@
21476
21391
  {
21477
21392
  "lang": "shell",
21478
21393
  "label": "curl",
21479
- "source": "curl -X POST https://api.wspc.ai/todo/items \\\n -H \"Authorization: Bearer $WSPC_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"title\":\"Buy milk\",\"due_at\":\"2026-06-01\"}'"
21394
+ "source": "curl -X POST https://api.wspc.ai/todo/recurrence-rules \\\n -H \"Authorization: Bearer $WSPC_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"title\":\"Draft weekly review\",\"rrule\":\"FREQ=WEEKLY;BYDAY=MO\",\"dtstart\":\"2026-05-18\",\"project_id\":\"prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\"}'"
21480
21395
  },
21481
21396
  {
21482
21397
  "lang": "bash",
21483
21398
  "label": "wspc CLI",
21484
- "source": "wspc todo add \"Buy milk\" --due 2026-06-01"
21485
- },
21486
- {
21487
- "lang": "typescript",
21488
- "label": "@wspc/client",
21489
- "source": "import { TodoClient } from \"@wspc/client\"\nconst todo = new TodoClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait todo.create({ title: \"Buy milk\", due_at: \"2026-06-01\" })"
21399
+ "source": "wspc todo rrule add \"Draft weekly review\" --rrule \"FREQ=WEEKLY;BYDAY=MO\" --dtstart 2026-05-18 --project prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
21490
21400
  }
21491
21401
  ],
21492
21402
  "requestBody": {
21493
21403
  "content": {
21494
21404
  "application/json": {
21495
21405
  "schema": {
21496
- "$ref": "#/components/schemas/CreateTodoBody"
21406
+ "$ref": "#/components/schemas/CreateRecurrenceRuleBody"
21497
21407
  },
21498
21408
  "examples": {
21499
21409
  "minimal": {
21500
- "summary": "Create a root-level todo with just a title",
21410
+ "summary": "Weekly recurrence anchored on a Monday",
21501
21411
  "value": {
21502
- "title": "Buy milk"
21412
+ "rrule": "FREQ=WEEKLY;BYDAY=MO",
21413
+ "dtstart": "2026-05-18",
21414
+ "title": "Draft weekly review",
21415
+ "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
21503
21416
  }
21504
21417
  },
21505
21418
  "full": {
21506
- "summary": "Create a child todo with description, status, and due date",
21419
+ "summary": "Weekly recurrence with description + parent",
21507
21420
  "value": {
21508
- "title": "Draft outline",
21421
+ "rrule": "FREQ=WEEKLY;BYDAY=MO",
21422
+ "dtstart": "2026-05-18",
21423
+ "title": "Draft weekly review",
21509
21424
  "description": "See PRD for context",
21510
21425
  "parent_id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21511
- "status": "in_progress",
21512
- "due_at": "2026-06-01"
21426
+ "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
21513
21427
  }
21514
21428
  }
21515
21429
  }
@@ -21518,28 +21432,28 @@
21518
21432
  },
21519
21433
  "responses": {
21520
21434
  "201": {
21521
- "description": "The todo was created. The response carries the full row including server-assigned `id`, `version`, and `created_at`.",
21435
+ "description": "The rule was created. `materialized_instance_count` reports how many todo instances were materialized immediately within the 14-day horizon.",
21522
21436
  "content": {
21523
21437
  "application/json": {
21524
21438
  "schema": {
21525
- "$ref": "#/components/schemas/Todo"
21439
+ "$ref": "#/components/schemas/CreateRecurrenceRuleResponse"
21526
21440
  },
21527
21441
  "examples": {
21528
21442
  "happyPath": {
21529
- "summary": "Active todo with a due date",
21443
+ "summary": "Weekly rule with 2 instances materialized in the 14-day window",
21530
21444
  "value": {
21531
- "id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21532
- "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21533
- "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21534
- "title": "Buy milk",
21535
- "description": "Use refundable rate",
21536
- "status": "open",
21537
- "parent_id": null,
21538
- "child_count": 0,
21539
- "version": 1,
21540
- "created_at": 1748736000000,
21541
- "updated_at": 1748736000000,
21542
- "due_at": "2026-06-01"
21445
+ "rule": {
21446
+ "id": "tdr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21447
+ "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21448
+ "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21449
+ "rrule": "FREQ=WEEKLY;BYDAY=MO",
21450
+ "dtstart": "2026-05-18",
21451
+ "version": 1,
21452
+ "created_at": 1748736000000,
21453
+ "updated_at": 1748736000000
21454
+ },
21455
+ "template_todo_id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21456
+ "materialized_instance_count": 2
21543
21457
  }
21544
21458
  }
21545
21459
  }
@@ -21872,40 +21786,31 @@
21872
21786
  }
21873
21787
  },
21874
21788
  "get": {
21875
- "operationId": "todo_list",
21789
+ "operationId": "recurrence_rule_list",
21876
21790
  "tags": [
21877
- "Todos"
21791
+ "RecurrenceRules"
21878
21792
  ],
21879
21793
  "x-cli": {
21880
- "command": "todo ls",
21881
- "aliases": {
21882
- "project": "p",
21883
- "status": "s"
21884
- },
21794
+ "command": "todo rule ls",
21885
21795
  "examples": [
21886
- "wspc todo ls",
21887
- "wspc todo ls --status open",
21888
- "wspc todo ls --project prj_xxx"
21796
+ "wspc todo rule ls"
21889
21797
  ],
21890
21798
  "display": {
21891
21799
  "shape": "list",
21892
21800
  "columns": [
21893
21801
  "id",
21894
- "status",
21895
- "title",
21896
- "due_at"
21802
+ "rrule",
21803
+ "dtstart"
21897
21804
  ],
21898
21805
  "format": {
21899
21806
  "id": "id-short",
21900
- "status": "status-badge",
21901
- "title": "truncate",
21902
- "due_at": "relative-time"
21807
+ "rrule": "truncate"
21903
21808
  },
21904
- "emptyMessage": "no todos"
21809
+ "emptyMessage": "no recurrence rules"
21905
21810
  }
21906
21811
  },
21907
- "summary": "List todos with filters",
21908
- "description": "### 🎯 Overview & Purpose\nReturn the caller's active or archived todos, with comprehensive options to filter by project, parent task, status, due-date window, and template visibility.\n\n### 🔍 When to Use\n* Use this to render the main todo board dashboard, query items due in a specific timeframe (using `due_after` and `due_before`), or lazy-load subtasks for an expanded parent todo by passing its ID.\n\n### 💡 Key Features & Constraints\n* **Required Parameter**: The `project_id` query parameter is strictly required and must match an active project.\n* **Parent Tasks**: Omitting `parent_id` lists root-level todos by default. Pass a todo id to list direct children of that specific task.\n* **Multi-Status Filters**: Multi-value `status` query is supported by repeating the parameter, e.g., `?status=open&status=in_progress`.\n* **Due-Date Windowing**: The `due_after` filter is inclusive, while `due_before` is exclusive, forming a half-open window `[due_after, due_before)`. Both parameters exclude todos with no due date.\n* **Template & Soft-Delete Visibility**: Soft-deleted todos are hidden unless `include_deleted=true`. Template todos backing recurrence rules are hidden unless `include_templates=true`.\n* **Custom-Field Filters (`cf.<key>=<value>`)**: Repeatable dynamic-prefix query parameters whose name follows the `cf.<key>` pattern (e.g. `?cf.priority=high&cf.team=eng`). Each pair is ANDed; for `string_array` custom fields the match is positive when the array contains the value. Keys must be declared on the project's todo type schema. Because the prefix is dynamic, these parameters cannot be expressed in the JSON Schema below — clients must construct them from the URL query string directly.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if `project_id` is missing, or if query parameters fail schema validation.",
21812
+ "summary": "List recurring todo rules",
21813
+ "description": "### 🎯 Overview & Purpose\nReturn all active recurrence rules within a specific project owned by the caller.\n\n### 🔍 When to Use\n* Use this to render rule management panels, list scheduled automation templates, or inspect active rules.\n\n### 💡 Key Features & Constraints\n* **Project Scope**: The `project_id` query parameter is strictly required.\n* **Exclusion**: Soft-deleted/archived rules are excluded from the response by default.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if `project_id` query filter is omitted.",
21909
21814
  "security": [
21910
21815
  {
21911
21816
  "bearerAuth": []
@@ -21915,17 +21820,12 @@
21915
21820
  {
21916
21821
  "lang": "shell",
21917
21822
  "label": "curl",
21918
- "source": "curl -G https://api.wspc.ai/todo/items \\\n -H \"Authorization: Bearer $WSPC_API_KEY\" \\\n --data-urlencode \"status=open\" \\\n --data-urlencode \"status=in_progress\""
21823
+ "source": "curl https://api.wspc.ai/todo/recurrence-rules \\\n -H \"Authorization: Bearer $WSPC_API_KEY\""
21919
21824
  },
21920
21825
  {
21921
21826
  "lang": "bash",
21922
21827
  "label": "wspc CLI",
21923
- "source": "wspc todo ls --status open in_progress"
21924
- },
21925
- {
21926
- "lang": "typescript",
21927
- "label": "@wspc/client",
21928
- "source": "import { TodoClient } from \"@wspc/client\"\nconst todo = new TodoClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait todo.list({ status: [\"open\", \"in_progress\"] })"
21828
+ "source": "wspc todo rrule ls"
21929
21829
  }
21930
21830
  ],
21931
21831
  "parameters": [
@@ -21933,10 +21833,10 @@
21933
21833
  "schema": {
21934
21834
  "type": "string",
21935
21835
  "minLength": 1,
21936
- "description": "Filter by project. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND."
21836
+ "description": "Project id filter. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND."
21937
21837
  },
21938
21838
  "required": true,
21939
- "description": "Filter by project. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.",
21839
+ "description": "Project id filter. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.",
21940
21840
  "name": "project_id",
21941
21841
  "in": "query"
21942
21842
  },
@@ -21947,182 +21847,1846 @@
21947
21847
  "required": false,
21948
21848
  "name": "user_id",
21949
21849
  "in": "query"
21950
- },
21951
- {
21952
- "schema": {
21953
- "type": "string"
21954
- },
21955
- "required": false,
21956
- "name": "parent_id",
21957
- "in": "query"
21958
- },
21959
- {
21960
- "schema": {
21961
- "anyOf": [
21962
- {
21963
- "type": "string"
21850
+ }
21851
+ ],
21852
+ "responses": {
21853
+ "200": {
21854
+ "description": "Active recurrence rules for the caller. Empty `rules` array when none are configured.",
21855
+ "content": {
21856
+ "application/json": {
21857
+ "schema": {
21858
+ "$ref": "#/components/schemas/ListRecurrenceRulesResponse"
21964
21859
  },
21965
- {
21966
- "type": "array",
21967
- "items": {
21968
- "type": "string"
21860
+ "examples": {
21861
+ "happyPath": {
21862
+ "summary": "Single weekly rule configured",
21863
+ "value": {
21864
+ "rules": [
21865
+ {
21866
+ "id": "tdr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21867
+ "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21868
+ "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
21869
+ "rrule": "FREQ=WEEKLY;BYDAY=MO",
21870
+ "dtstart": "2026-05-18",
21871
+ "version": 1,
21872
+ "created_at": 1748736000000,
21873
+ "updated_at": 1748736000000
21874
+ }
21875
+ ]
21876
+ }
21877
+ },
21878
+ "empty": {
21879
+ "summary": "No recurring rules",
21880
+ "value": {
21881
+ "rules": []
21882
+ }
21969
21883
  }
21970
21884
  }
21971
- ]
21972
- },
21973
- "required": false,
21974
- "name": "status",
21975
- "in": "query"
21885
+ }
21886
+ }
21976
21887
  },
21977
- {
21978
- "schema": {
21979
- "anyOf": [
21980
- {
21981
- "type": "string"
21982
- },
21983
- {
21984
- "type": "array",
21985
- "items": {
21986
- "type": "string"
21987
- }
21988
- }
21989
- ]
21990
- },
21991
- "required": false,
21992
- "name": "include_deleted",
21993
- "in": "query"
21994
- },
21995
- {
21996
- "schema": {
21997
- "anyOf": [
21998
- {
21999
- "type": "string"
21888
+ "400": {
21889
+ "description": "Request validation failed. The body, query, or path parameters did not match the operation's schema.",
21890
+ "content": {
21891
+ "application/json": {
21892
+ "schema": {
21893
+ "type": "object",
21894
+ "properties": {
21895
+ "error": {
21896
+ "type": "object",
21897
+ "properties": {
21898
+ "code": {
21899
+ "type": "string"
21900
+ },
21901
+ "message": {
21902
+ "type": "string"
21903
+ },
21904
+ "extra": {
21905
+ "type": "object",
21906
+ "additionalProperties": {}
21907
+ }
21908
+ },
21909
+ "required": [
21910
+ "code",
21911
+ "message"
21912
+ ]
21913
+ }
21914
+ },
21915
+ "required": [
21916
+ "error"
21917
+ ]
22000
21918
  },
22001
- {
22002
- "type": "array",
22003
- "items": {
22004
- "type": "string"
21919
+ "examples": {
21920
+ "validationError": {
21921
+ "summary": "Body failed schema validation",
21922
+ "value": {
21923
+ "error": {
21924
+ "code": "VALIDATION_ERROR",
21925
+ "message": "title must not be empty"
21926
+ }
21927
+ }
22005
21928
  }
22006
21929
  }
22007
- ]
22008
- },
22009
- "required": false,
22010
- "name": "include_templates",
22011
- "in": "query"
22012
- },
22013
- {
22014
- "schema": {
22015
- "type": "string"
22016
- },
22017
- "required": false,
22018
- "name": "due_after",
22019
- "in": "query"
22020
- },
22021
- {
22022
- "schema": {
22023
- "type": "string"
22024
- },
22025
- "required": false,
22026
- "name": "due_before",
22027
- "in": "query"
22028
- },
22029
- {
22030
- "schema": {
22031
- "type": "string",
22032
- "minLength": 1
22033
- },
22034
- "required": false,
22035
- "name": "type_id",
22036
- "in": "query"
22037
- },
22038
- {
22039
- "schema": {
22040
- "type": "string",
22041
- "minLength": 1
22042
- },
22043
- "required": false,
22044
- "name": "sort_by",
22045
- "in": "query"
22046
- },
22047
- {
22048
- "schema": {
22049
- "type": "string",
22050
- "enum": [
22051
- "asc",
22052
- "desc"
22053
- ]
22054
- },
22055
- "required": false,
22056
- "name": "order",
22057
- "in": "query"
21930
+ }
21931
+ }
22058
21932
  },
22059
- {
22060
- "schema": {
22061
- "anyOf": [
22062
- {
22063
- "type": "string"
21933
+ "401": {
21934
+ "description": "Authentication is required but missing or invalid. The Bearer token (API key or OAuth access token) was absent, malformed, or rejected.",
21935
+ "content": {
21936
+ "application/json": {
21937
+ "schema": {
21938
+ "type": "object",
21939
+ "properties": {
21940
+ "error": {
21941
+ "type": "object",
21942
+ "properties": {
21943
+ "code": {
21944
+ "type": "string"
21945
+ },
21946
+ "message": {
21947
+ "type": "string"
21948
+ },
21949
+ "extra": {
21950
+ "type": "object",
21951
+ "additionalProperties": {}
21952
+ }
21953
+ },
21954
+ "required": [
21955
+ "code",
21956
+ "message"
21957
+ ]
21958
+ }
21959
+ },
21960
+ "required": [
21961
+ "error"
21962
+ ]
22064
21963
  },
22065
- {
22066
- "type": "array",
22067
- "items": {
22068
- "type": "string"
21964
+ "examples": {
21965
+ "authRequired": {
21966
+ "summary": "Missing Authorization header",
21967
+ "value": {
21968
+ "error": {
21969
+ "code": "AUTH_REQUIRED",
21970
+ "message": "missing bearer token"
21971
+ }
21972
+ }
22069
21973
  }
22070
21974
  }
22071
- ]
22072
- },
22073
- "required": false,
22074
- "name": "include_orphan_fields",
22075
- "in": "query"
22076
- }
22077
- ],
22078
- "responses": {
22079
- "200": {
22080
- "description": "List of todos matching the filters. Empty `todos` array when nothing matches.",
21975
+ }
21976
+ }
21977
+ },
21978
+ "403": {
21979
+ "description": "The caller is authenticated but not permitted to perform this operation on the target resource.",
22081
21980
  "content": {
22082
21981
  "application/json": {
22083
21982
  "schema": {
22084
- "$ref": "#/components/schemas/ListTodosResponse"
21983
+ "type": "object",
21984
+ "properties": {
21985
+ "error": {
21986
+ "type": "object",
21987
+ "properties": {
21988
+ "code": {
21989
+ "type": "string"
21990
+ },
21991
+ "message": {
21992
+ "type": "string"
21993
+ },
21994
+ "extra": {
21995
+ "type": "object",
21996
+ "additionalProperties": {}
21997
+ }
21998
+ },
21999
+ "required": [
22000
+ "code",
22001
+ "message"
22002
+ ]
22003
+ }
22004
+ },
22005
+ "required": [
22006
+ "error"
22007
+ ]
22085
22008
  },
22086
22009
  "examples": {
22087
- "happyPath": {
22088
- "summary": "Two active root-level todos",
22010
+ "forbidden": {
22011
+ "summary": "Caller does not own the resource",
22089
22012
  "value": {
22090
- "todos": [
22091
- {
22092
- "id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
22093
- "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
22094
- "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
22095
- "title": "Buy milk",
22096
- "description": "Use refundable rate",
22097
- "status": "open",
22098
- "parent_id": null,
22099
- "child_count": 0,
22100
- "version": 1,
22101
- "created_at": 1748736000000,
22102
- "updated_at": 1748736000000,
22103
- "due_at": "2026-06-01"
22013
+ "error": {
22014
+ "code": "FORBIDDEN",
22015
+ "message": "not allowed"
22016
+ }
22017
+ }
22018
+ }
22019
+ }
22020
+ }
22021
+ }
22022
+ },
22023
+ "404": {
22024
+ "description": "The target resource does not exist or is not visible to the caller. Soft-deleted resources are treated as not found unless an `include_deleted` flag is set.",
22025
+ "content": {
22026
+ "application/json": {
22027
+ "schema": {
22028
+ "type": "object",
22029
+ "properties": {
22030
+ "error": {
22031
+ "type": "object",
22032
+ "properties": {
22033
+ "code": {
22034
+ "type": "string"
22104
22035
  },
22105
- {
22106
- "id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3G",
22107
- "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
22108
- "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
22109
- "title": "Submit expenses",
22110
- "status": "in_progress",
22111
- "parent_id": null,
22112
- "child_count": 0,
22113
- "version": 1,
22114
- "created_at": 1748736000000,
22115
- "updated_at": 1748736000000
22036
+ "message": {
22037
+ "type": "string"
22038
+ },
22039
+ "extra": {
22040
+ "type": "object",
22041
+ "additionalProperties": {}
22116
22042
  }
22043
+ },
22044
+ "required": [
22045
+ "code",
22046
+ "message"
22117
22047
  ]
22118
22048
  }
22119
22049
  },
22120
- "empty": {
22121
- "summary": "No matching todos",
22122
- "value": {
22123
- "todos": []
22124
- }
22125
- }
22050
+ "required": [
22051
+ "error"
22052
+ ]
22053
+ },
22054
+ "examples": {
22055
+ "notFound": {
22056
+ "summary": "Resource id is unknown to the service",
22057
+ "value": {
22058
+ "error": {
22059
+ "code": "NOT_FOUND",
22060
+ "message": "todo not found"
22061
+ }
22062
+ }
22063
+ }
22064
+ }
22065
+ }
22066
+ }
22067
+ },
22068
+ "409": {
22069
+ "description": "Optimistic-lock conflict. The supplied `expected_version` does not match the server's current version. Refetch the resource and retry.",
22070
+ "content": {
22071
+ "application/json": {
22072
+ "schema": {
22073
+ "type": "object",
22074
+ "properties": {
22075
+ "error": {
22076
+ "type": "object",
22077
+ "properties": {
22078
+ "code": {
22079
+ "type": "string"
22080
+ },
22081
+ "message": {
22082
+ "type": "string"
22083
+ },
22084
+ "extra": {
22085
+ "type": "object",
22086
+ "additionalProperties": {}
22087
+ }
22088
+ },
22089
+ "required": [
22090
+ "code",
22091
+ "message"
22092
+ ]
22093
+ }
22094
+ },
22095
+ "required": [
22096
+ "error"
22097
+ ]
22098
+ },
22099
+ "examples": {
22100
+ "versionConflict": {
22101
+ "summary": "expected_version does not match server version",
22102
+ "value": {
22103
+ "error": {
22104
+ "code": "VERSION_CONFLICT",
22105
+ "message": "expected_version 3 but current is 4",
22106
+ "extra": {
22107
+ "expected_version": 3,
22108
+ "actual_version": 4
22109
+ }
22110
+ }
22111
+ }
22112
+ }
22113
+ }
22114
+ }
22115
+ }
22116
+ },
22117
+ "429": {
22118
+ "description": "Rate limit exceeded. Retry after the duration in `error.extra.retry_after_seconds`. `limit_kind` identifies which bucket was exhausted.",
22119
+ "content": {
22120
+ "application/json": {
22121
+ "schema": {
22122
+ "type": "object",
22123
+ "properties": {
22124
+ "error": {
22125
+ "type": "object",
22126
+ "properties": {
22127
+ "code": {
22128
+ "type": "string"
22129
+ },
22130
+ "message": {
22131
+ "type": "string"
22132
+ },
22133
+ "extra": {
22134
+ "type": "object",
22135
+ "additionalProperties": {}
22136
+ }
22137
+ },
22138
+ "required": [
22139
+ "code",
22140
+ "message"
22141
+ ]
22142
+ }
22143
+ },
22144
+ "required": [
22145
+ "error"
22146
+ ]
22147
+ },
22148
+ "examples": {
22149
+ "rateLimited": {
22150
+ "summary": "Per-key rate limit hit",
22151
+ "value": {
22152
+ "error": {
22153
+ "code": "RATE_LIMITED",
22154
+ "message": "rate limit exceeded",
22155
+ "extra": {
22156
+ "retry_after_seconds": 60,
22157
+ "limit_kind": "authenticated_per_key"
22158
+ }
22159
+ }
22160
+ }
22161
+ }
22162
+ }
22163
+ }
22164
+ }
22165
+ },
22166
+ "500": {
22167
+ "description": "Unhandled server error. The request was well-formed but the service failed unexpectedly. Safe to retry idempotent operations.",
22168
+ "content": {
22169
+ "application/json": {
22170
+ "schema": {
22171
+ "type": "object",
22172
+ "properties": {
22173
+ "error": {
22174
+ "type": "object",
22175
+ "properties": {
22176
+ "code": {
22177
+ "type": "string"
22178
+ },
22179
+ "message": {
22180
+ "type": "string"
22181
+ },
22182
+ "extra": {
22183
+ "type": "object",
22184
+ "additionalProperties": {}
22185
+ }
22186
+ },
22187
+ "required": [
22188
+ "code",
22189
+ "message"
22190
+ ]
22191
+ }
22192
+ },
22193
+ "required": [
22194
+ "error"
22195
+ ]
22196
+ },
22197
+ "examples": {
22198
+ "internalError": {
22199
+ "summary": "Unhandled exception",
22200
+ "value": {
22201
+ "error": {
22202
+ "code": "INTERNAL_ERROR",
22203
+ "message": "internal error"
22204
+ }
22205
+ }
22206
+ }
22207
+ }
22208
+ }
22209
+ }
22210
+ }
22211
+ }
22212
+ }
22213
+ },
22214
+ "/todo/items": {
22215
+ "post": {
22216
+ "operationId": "todo_create",
22217
+ "tags": [
22218
+ "Todos"
22219
+ ],
22220
+ "x-cli": {
22221
+ "command": "todo add",
22222
+ "positional": [
22223
+ "title"
22224
+ ],
22225
+ "aliases": {
22226
+ "project": "p"
22227
+ },
22228
+ "examples": [
22229
+ "wspc todo add \"Buy milk\"",
22230
+ "wspc todo add \"Buy milk\" --project prj_xxx"
22231
+ ],
22232
+ "display": {
22233
+ "shape": "object",
22234
+ "format": {
22235
+ "id": "id-short",
22236
+ "user_id": "id-short",
22237
+ "project_id": "id-short",
22238
+ "parent_id": "id-short",
22239
+ "type_id": "id-short",
22240
+ "status": "status-badge",
22241
+ "due_at": "relative-time",
22242
+ "created_at": "relative-time",
22243
+ "updated_at": "relative-time",
22244
+ "deleted_at": "relative-time"
22245
+ }
22246
+ }
22247
+ },
22248
+ "summary": "Create a todo",
22249
+ "description": "### 🎯 Overview & Purpose\nCreate a new todo item under a specified project. This can either be a standalone root-level todo or a nested subtask attached to an existing root todo.\n\n### 🔍 When to Use\n* Use this to capture a fresh work item, document an ongoing task, or break a larger root todo into subtasks by creating child todos under it.\n\n### 💡 Key Features & Constraints\n* **One-Level Nesting Limit**: WSPC supports a maximum of one level of task nesting (Root ➔ Child). A root-level todo can have children, but a child todo cannot have further subtasks. Setting a child todo as a parent will fail and trigger a `PARENT_IS_CHILD` error.\n* **Description Handling**: Passing a non-empty string stores the description; passing `\"\"` explicitly stores an empty string. Passing `null` is strictly rejected.\n* **Due Date Format**: Accepts an ISO-8601 date-only format (`YYYY-MM-DD`). Pass `\"\"` or omit the field to skip setting a due date.\n* **Project Binding**: Every todo must belong to a valid active project (`project_id`).\n\n### ⚠️ Common Errors & Troubleshooting\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if required fields are missing, if `due_at` violates the `YYYY-MM-DD` format, or if `title` exceeds 500 characters.\n* **`PARENT_IS_CHILD` (HTTP 400)**: Thrown if the target `parent_id` refers to a todo that is itself already a child todo.\n* **`WOULD_CREATE_CYCLE` (HTTP 400)**: Thrown if `parent_id` points to the todo's own ID.\n* **`NOT_FOUND` (HTTP 404)**: Thrown if the specified `project_id` or `parent_id` does not exist or has been soft-deleted.",
22250
+ "security": [
22251
+ {
22252
+ "bearerAuth": []
22253
+ }
22254
+ ],
22255
+ "x-codeSamples": [
22256
+ {
22257
+ "lang": "shell",
22258
+ "label": "curl",
22259
+ "source": "curl -X POST https://api.wspc.ai/todo/items \\\n -H \"Authorization: Bearer $WSPC_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"title\":\"Buy milk\",\"due_at\":\"2026-06-01\"}'"
22260
+ },
22261
+ {
22262
+ "lang": "bash",
22263
+ "label": "wspc CLI",
22264
+ "source": "wspc todo add \"Buy milk\" --due 2026-06-01"
22265
+ }
22266
+ ],
22267
+ "requestBody": {
22268
+ "content": {
22269
+ "application/json": {
22270
+ "schema": {
22271
+ "$ref": "#/components/schemas/CreateTodoBody"
22272
+ },
22273
+ "examples": {
22274
+ "minimal": {
22275
+ "summary": "Create a root-level todo with just a title",
22276
+ "value": {
22277
+ "title": "Buy milk"
22278
+ }
22279
+ },
22280
+ "full": {
22281
+ "summary": "Create a child todo with description, status, and due date",
22282
+ "value": {
22283
+ "title": "Draft outline",
22284
+ "description": "See PRD for context",
22285
+ "parent_id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
22286
+ "status": "in_progress",
22287
+ "due_at": "2026-06-01"
22288
+ }
22289
+ }
22290
+ }
22291
+ }
22292
+ }
22293
+ },
22294
+ "responses": {
22295
+ "201": {
22296
+ "description": "The todo was created. The response carries the full row including server-assigned `id`, `version`, and `created_at`.",
22297
+ "content": {
22298
+ "application/json": {
22299
+ "schema": {
22300
+ "$ref": "#/components/schemas/Todo"
22301
+ },
22302
+ "examples": {
22303
+ "happyPath": {
22304
+ "summary": "Active todo with a due date",
22305
+ "value": {
22306
+ "id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
22307
+ "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
22308
+ "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
22309
+ "title": "Buy milk",
22310
+ "description": "Use refundable rate",
22311
+ "status": "open",
22312
+ "parent_id": null,
22313
+ "child_count": 0,
22314
+ "version": 1,
22315
+ "created_at": 1748736000000,
22316
+ "updated_at": 1748736000000,
22317
+ "due_at": "2026-06-01"
22318
+ }
22319
+ }
22320
+ }
22321
+ }
22322
+ }
22323
+ },
22324
+ "400": {
22325
+ "description": "Request validation failed. The body, query, or path parameters did not match the operation's schema.",
22326
+ "content": {
22327
+ "application/json": {
22328
+ "schema": {
22329
+ "type": "object",
22330
+ "properties": {
22331
+ "error": {
22332
+ "type": "object",
22333
+ "properties": {
22334
+ "code": {
22335
+ "type": "string"
22336
+ },
22337
+ "message": {
22338
+ "type": "string"
22339
+ },
22340
+ "extra": {
22341
+ "type": "object",
22342
+ "additionalProperties": {}
22343
+ }
22344
+ },
22345
+ "required": [
22346
+ "code",
22347
+ "message"
22348
+ ]
22349
+ }
22350
+ },
22351
+ "required": [
22352
+ "error"
22353
+ ]
22354
+ },
22355
+ "examples": {
22356
+ "validationError": {
22357
+ "summary": "Body failed schema validation",
22358
+ "value": {
22359
+ "error": {
22360
+ "code": "VALIDATION_ERROR",
22361
+ "message": "title must not be empty"
22362
+ }
22363
+ }
22364
+ }
22365
+ }
22366
+ }
22367
+ }
22368
+ },
22369
+ "401": {
22370
+ "description": "Authentication is required but missing or invalid. The Bearer token (API key or OAuth access token) was absent, malformed, or rejected.",
22371
+ "content": {
22372
+ "application/json": {
22373
+ "schema": {
22374
+ "type": "object",
22375
+ "properties": {
22376
+ "error": {
22377
+ "type": "object",
22378
+ "properties": {
22379
+ "code": {
22380
+ "type": "string"
22381
+ },
22382
+ "message": {
22383
+ "type": "string"
22384
+ },
22385
+ "extra": {
22386
+ "type": "object",
22387
+ "additionalProperties": {}
22388
+ }
22389
+ },
22390
+ "required": [
22391
+ "code",
22392
+ "message"
22393
+ ]
22394
+ }
22395
+ },
22396
+ "required": [
22397
+ "error"
22398
+ ]
22399
+ },
22400
+ "examples": {
22401
+ "authRequired": {
22402
+ "summary": "Missing Authorization header",
22403
+ "value": {
22404
+ "error": {
22405
+ "code": "AUTH_REQUIRED",
22406
+ "message": "missing bearer token"
22407
+ }
22408
+ }
22409
+ }
22410
+ }
22411
+ }
22412
+ }
22413
+ },
22414
+ "403": {
22415
+ "description": "The caller is authenticated but not permitted to perform this operation on the target resource.",
22416
+ "content": {
22417
+ "application/json": {
22418
+ "schema": {
22419
+ "type": "object",
22420
+ "properties": {
22421
+ "error": {
22422
+ "type": "object",
22423
+ "properties": {
22424
+ "code": {
22425
+ "type": "string"
22426
+ },
22427
+ "message": {
22428
+ "type": "string"
22429
+ },
22430
+ "extra": {
22431
+ "type": "object",
22432
+ "additionalProperties": {}
22433
+ }
22434
+ },
22435
+ "required": [
22436
+ "code",
22437
+ "message"
22438
+ ]
22439
+ }
22440
+ },
22441
+ "required": [
22442
+ "error"
22443
+ ]
22444
+ },
22445
+ "examples": {
22446
+ "forbidden": {
22447
+ "summary": "Caller does not own the resource",
22448
+ "value": {
22449
+ "error": {
22450
+ "code": "FORBIDDEN",
22451
+ "message": "not allowed"
22452
+ }
22453
+ }
22454
+ }
22455
+ }
22456
+ }
22457
+ }
22458
+ },
22459
+ "404": {
22460
+ "description": "The target resource does not exist or is not visible to the caller. Soft-deleted resources are treated as not found unless an `include_deleted` flag is set.",
22461
+ "content": {
22462
+ "application/json": {
22463
+ "schema": {
22464
+ "type": "object",
22465
+ "properties": {
22466
+ "error": {
22467
+ "type": "object",
22468
+ "properties": {
22469
+ "code": {
22470
+ "type": "string"
22471
+ },
22472
+ "message": {
22473
+ "type": "string"
22474
+ },
22475
+ "extra": {
22476
+ "type": "object",
22477
+ "additionalProperties": {}
22478
+ }
22479
+ },
22480
+ "required": [
22481
+ "code",
22482
+ "message"
22483
+ ]
22484
+ }
22485
+ },
22486
+ "required": [
22487
+ "error"
22488
+ ]
22489
+ },
22490
+ "examples": {
22491
+ "notFound": {
22492
+ "summary": "Resource id is unknown to the service",
22493
+ "value": {
22494
+ "error": {
22495
+ "code": "NOT_FOUND",
22496
+ "message": "todo not found"
22497
+ }
22498
+ }
22499
+ }
22500
+ }
22501
+ }
22502
+ }
22503
+ },
22504
+ "409": {
22505
+ "description": "Optimistic-lock conflict. The supplied `expected_version` does not match the server's current version. Refetch the resource and retry.",
22506
+ "content": {
22507
+ "application/json": {
22508
+ "schema": {
22509
+ "type": "object",
22510
+ "properties": {
22511
+ "error": {
22512
+ "type": "object",
22513
+ "properties": {
22514
+ "code": {
22515
+ "type": "string"
22516
+ },
22517
+ "message": {
22518
+ "type": "string"
22519
+ },
22520
+ "extra": {
22521
+ "type": "object",
22522
+ "additionalProperties": {}
22523
+ }
22524
+ },
22525
+ "required": [
22526
+ "code",
22527
+ "message"
22528
+ ]
22529
+ }
22530
+ },
22531
+ "required": [
22532
+ "error"
22533
+ ]
22534
+ },
22535
+ "examples": {
22536
+ "versionConflict": {
22537
+ "summary": "expected_version does not match server version",
22538
+ "value": {
22539
+ "error": {
22540
+ "code": "VERSION_CONFLICT",
22541
+ "message": "expected_version 3 but current is 4",
22542
+ "extra": {
22543
+ "expected_version": 3,
22544
+ "actual_version": 4
22545
+ }
22546
+ }
22547
+ }
22548
+ }
22549
+ }
22550
+ }
22551
+ }
22552
+ },
22553
+ "429": {
22554
+ "description": "Rate limit exceeded. Retry after the duration in `error.extra.retry_after_seconds`. `limit_kind` identifies which bucket was exhausted.",
22555
+ "content": {
22556
+ "application/json": {
22557
+ "schema": {
22558
+ "type": "object",
22559
+ "properties": {
22560
+ "error": {
22561
+ "type": "object",
22562
+ "properties": {
22563
+ "code": {
22564
+ "type": "string"
22565
+ },
22566
+ "message": {
22567
+ "type": "string"
22568
+ },
22569
+ "extra": {
22570
+ "type": "object",
22571
+ "additionalProperties": {}
22572
+ }
22573
+ },
22574
+ "required": [
22575
+ "code",
22576
+ "message"
22577
+ ]
22578
+ }
22579
+ },
22580
+ "required": [
22581
+ "error"
22582
+ ]
22583
+ },
22584
+ "examples": {
22585
+ "rateLimited": {
22586
+ "summary": "Per-key rate limit hit",
22587
+ "value": {
22588
+ "error": {
22589
+ "code": "RATE_LIMITED",
22590
+ "message": "rate limit exceeded",
22591
+ "extra": {
22592
+ "retry_after_seconds": 60,
22593
+ "limit_kind": "authenticated_per_key"
22594
+ }
22595
+ }
22596
+ }
22597
+ }
22598
+ }
22599
+ }
22600
+ }
22601
+ },
22602
+ "500": {
22603
+ "description": "Unhandled server error. The request was well-formed but the service failed unexpectedly. Safe to retry idempotent operations.",
22604
+ "content": {
22605
+ "application/json": {
22606
+ "schema": {
22607
+ "type": "object",
22608
+ "properties": {
22609
+ "error": {
22610
+ "type": "object",
22611
+ "properties": {
22612
+ "code": {
22613
+ "type": "string"
22614
+ },
22615
+ "message": {
22616
+ "type": "string"
22617
+ },
22618
+ "extra": {
22619
+ "type": "object",
22620
+ "additionalProperties": {}
22621
+ }
22622
+ },
22623
+ "required": [
22624
+ "code",
22625
+ "message"
22626
+ ]
22627
+ }
22628
+ },
22629
+ "required": [
22630
+ "error"
22631
+ ]
22632
+ },
22633
+ "examples": {
22634
+ "internalError": {
22635
+ "summary": "Unhandled exception",
22636
+ "value": {
22637
+ "error": {
22638
+ "code": "INTERNAL_ERROR",
22639
+ "message": "internal error"
22640
+ }
22641
+ }
22642
+ }
22643
+ }
22644
+ }
22645
+ }
22646
+ }
22647
+ }
22648
+ },
22649
+ "get": {
22650
+ "operationId": "todo_list",
22651
+ "tags": [
22652
+ "Todos"
22653
+ ],
22654
+ "x-cli": {
22655
+ "command": "todo ls",
22656
+ "aliases": {
22657
+ "project": "p",
22658
+ "status": "s"
22659
+ },
22660
+ "examples": [
22661
+ "wspc todo ls",
22662
+ "wspc todo ls --status open",
22663
+ "wspc todo ls --project prj_xxx"
22664
+ ],
22665
+ "display": {
22666
+ "shape": "list",
22667
+ "columns": [
22668
+ "id",
22669
+ "status",
22670
+ "title",
22671
+ "due_at"
22672
+ ],
22673
+ "format": {
22674
+ "id": "id-short",
22675
+ "status": "status-badge",
22676
+ "title": "truncate",
22677
+ "due_at": "relative-time"
22678
+ },
22679
+ "emptyMessage": "no todos"
22680
+ }
22681
+ },
22682
+ "summary": "List todos with filters",
22683
+ "description": "### 🎯 Overview & Purpose\nReturn the caller's active or archived todos, with comprehensive options to filter by project, parent task, status, due-date window, and template visibility.\n\n### 🔍 When to Use\n* Use this to render the main todo board dashboard, query items due in a specific timeframe (using `due_after` and `due_before`), or lazy-load subtasks for an expanded parent todo by passing its ID.\n\n### 💡 Key Features & Constraints\n* **Required Parameter**: The `project_id` query parameter is strictly required and must match an active project.\n* **Parent Tasks**: Omitting `parent_id` lists root-level todos by default. Pass a todo id to list direct children of that specific task.\n* **Multi-Status Filters**: Multi-value `status` query is supported by repeating the parameter, e.g., `?status=open&status=in_progress`.\n* **Due-Date Windowing**: The `due_after` filter is inclusive, while `due_before` is exclusive, forming a half-open window `[due_after, due_before)`. Both parameters exclude todos with no due date.\n* **Template & Soft-Delete Visibility**: Soft-deleted todos are hidden unless `include_deleted=true`. Template todos backing recurrence rules are hidden unless `include_templates=true`.\n* **Custom-Field Filters (`cf.<key>=<value>`)**: Repeatable dynamic-prefix query parameters whose name follows the `cf.<key>` pattern (e.g. `?cf.priority=high&cf.team=eng`). Each pair is ANDed; for `string_array` custom fields the match is positive when the array contains the value. Keys must be declared on the project's todo type schema. Because the prefix is dynamic, these parameters cannot be expressed in the JSON Schema below — clients must construct them from the URL query string directly.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if `project_id` is missing, or if query parameters fail schema validation.",
22684
+ "security": [
22685
+ {
22686
+ "bearerAuth": []
22687
+ }
22688
+ ],
22689
+ "x-codeSamples": [
22690
+ {
22691
+ "lang": "shell",
22692
+ "label": "curl",
22693
+ "source": "curl -G https://api.wspc.ai/todo/items \\\n -H \"Authorization: Bearer $WSPC_API_KEY\" \\\n --data-urlencode \"status=open\" \\\n --data-urlencode \"status=in_progress\""
22694
+ },
22695
+ {
22696
+ "lang": "bash",
22697
+ "label": "wspc CLI",
22698
+ "source": "wspc todo ls --status open in_progress"
22699
+ }
22700
+ ],
22701
+ "parameters": [
22702
+ {
22703
+ "schema": {
22704
+ "type": "string",
22705
+ "minLength": 1,
22706
+ "description": "Filter by project. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND."
22707
+ },
22708
+ "required": true,
22709
+ "description": "Filter by project. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.",
22710
+ "name": "project_id",
22711
+ "in": "query"
22712
+ },
22713
+ {
22714
+ "schema": {
22715
+ "type": "string"
22716
+ },
22717
+ "required": false,
22718
+ "name": "user_id",
22719
+ "in": "query"
22720
+ },
22721
+ {
22722
+ "schema": {
22723
+ "type": "string"
22724
+ },
22725
+ "required": false,
22726
+ "name": "parent_id",
22727
+ "in": "query"
22728
+ },
22729
+ {
22730
+ "schema": {
22731
+ "anyOf": [
22732
+ {
22733
+ "type": "string"
22734
+ },
22735
+ {
22736
+ "type": "array",
22737
+ "items": {
22738
+ "type": "string"
22739
+ }
22740
+ }
22741
+ ]
22742
+ },
22743
+ "required": false,
22744
+ "name": "status",
22745
+ "in": "query"
22746
+ },
22747
+ {
22748
+ "schema": {
22749
+ "anyOf": [
22750
+ {
22751
+ "type": "string"
22752
+ },
22753
+ {
22754
+ "type": "array",
22755
+ "items": {
22756
+ "type": "string"
22757
+ }
22758
+ }
22759
+ ]
22760
+ },
22761
+ "required": false,
22762
+ "name": "include_deleted",
22763
+ "in": "query"
22764
+ },
22765
+ {
22766
+ "schema": {
22767
+ "anyOf": [
22768
+ {
22769
+ "type": "string"
22770
+ },
22771
+ {
22772
+ "type": "array",
22773
+ "items": {
22774
+ "type": "string"
22775
+ }
22776
+ }
22777
+ ]
22778
+ },
22779
+ "required": false,
22780
+ "name": "include_templates",
22781
+ "in": "query"
22782
+ },
22783
+ {
22784
+ "schema": {
22785
+ "type": "string"
22786
+ },
22787
+ "required": false,
22788
+ "name": "due_after",
22789
+ "in": "query"
22790
+ },
22791
+ {
22792
+ "schema": {
22793
+ "type": "string"
22794
+ },
22795
+ "required": false,
22796
+ "name": "due_before",
22797
+ "in": "query"
22798
+ },
22799
+ {
22800
+ "schema": {
22801
+ "type": "string",
22802
+ "minLength": 1
22803
+ },
22804
+ "required": false,
22805
+ "name": "type_id",
22806
+ "in": "query"
22807
+ },
22808
+ {
22809
+ "schema": {
22810
+ "type": "string",
22811
+ "minLength": 1
22812
+ },
22813
+ "required": false,
22814
+ "name": "sort_by",
22815
+ "in": "query"
22816
+ },
22817
+ {
22818
+ "schema": {
22819
+ "type": "string",
22820
+ "enum": [
22821
+ "asc",
22822
+ "desc"
22823
+ ]
22824
+ },
22825
+ "required": false,
22826
+ "name": "order",
22827
+ "in": "query"
22828
+ },
22829
+ {
22830
+ "schema": {
22831
+ "anyOf": [
22832
+ {
22833
+ "type": "string"
22834
+ },
22835
+ {
22836
+ "type": "array",
22837
+ "items": {
22838
+ "type": "string"
22839
+ }
22840
+ }
22841
+ ]
22842
+ },
22843
+ "required": false,
22844
+ "name": "include_orphan_fields",
22845
+ "in": "query"
22846
+ }
22847
+ ],
22848
+ "responses": {
22849
+ "200": {
22850
+ "description": "List of todos matching the filters. Empty `todos` array when nothing matches.",
22851
+ "content": {
22852
+ "application/json": {
22853
+ "schema": {
22854
+ "$ref": "#/components/schemas/ListTodosResponse"
22855
+ },
22856
+ "examples": {
22857
+ "happyPath": {
22858
+ "summary": "Two active root-level todos",
22859
+ "value": {
22860
+ "todos": [
22861
+ {
22862
+ "id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
22863
+ "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
22864
+ "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
22865
+ "title": "Buy milk",
22866
+ "description": "Use refundable rate",
22867
+ "status": "open",
22868
+ "parent_id": null,
22869
+ "child_count": 0,
22870
+ "version": 1,
22871
+ "created_at": 1748736000000,
22872
+ "updated_at": 1748736000000,
22873
+ "due_at": "2026-06-01"
22874
+ },
22875
+ {
22876
+ "id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3G",
22877
+ "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
22878
+ "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
22879
+ "title": "Submit expenses",
22880
+ "status": "in_progress",
22881
+ "parent_id": null,
22882
+ "child_count": 0,
22883
+ "version": 1,
22884
+ "created_at": 1748736000000,
22885
+ "updated_at": 1748736000000
22886
+ }
22887
+ ]
22888
+ }
22889
+ },
22890
+ "empty": {
22891
+ "summary": "No matching todos",
22892
+ "value": {
22893
+ "todos": []
22894
+ }
22895
+ }
22896
+ }
22897
+ }
22898
+ }
22899
+ },
22900
+ "400": {
22901
+ "description": "Request validation failed. The body, query, or path parameters did not match the operation's schema.",
22902
+ "content": {
22903
+ "application/json": {
22904
+ "schema": {
22905
+ "type": "object",
22906
+ "properties": {
22907
+ "error": {
22908
+ "type": "object",
22909
+ "properties": {
22910
+ "code": {
22911
+ "type": "string"
22912
+ },
22913
+ "message": {
22914
+ "type": "string"
22915
+ },
22916
+ "extra": {
22917
+ "type": "object",
22918
+ "additionalProperties": {}
22919
+ }
22920
+ },
22921
+ "required": [
22922
+ "code",
22923
+ "message"
22924
+ ]
22925
+ }
22926
+ },
22927
+ "required": [
22928
+ "error"
22929
+ ]
22930
+ },
22931
+ "examples": {
22932
+ "validationError": {
22933
+ "summary": "Body failed schema validation",
22934
+ "value": {
22935
+ "error": {
22936
+ "code": "VALIDATION_ERROR",
22937
+ "message": "title must not be empty"
22938
+ }
22939
+ }
22940
+ }
22941
+ }
22942
+ }
22943
+ }
22944
+ },
22945
+ "401": {
22946
+ "description": "Authentication is required but missing or invalid. The Bearer token (API key or OAuth access token) was absent, malformed, or rejected.",
22947
+ "content": {
22948
+ "application/json": {
22949
+ "schema": {
22950
+ "type": "object",
22951
+ "properties": {
22952
+ "error": {
22953
+ "type": "object",
22954
+ "properties": {
22955
+ "code": {
22956
+ "type": "string"
22957
+ },
22958
+ "message": {
22959
+ "type": "string"
22960
+ },
22961
+ "extra": {
22962
+ "type": "object",
22963
+ "additionalProperties": {}
22964
+ }
22965
+ },
22966
+ "required": [
22967
+ "code",
22968
+ "message"
22969
+ ]
22970
+ }
22971
+ },
22972
+ "required": [
22973
+ "error"
22974
+ ]
22975
+ },
22976
+ "examples": {
22977
+ "authRequired": {
22978
+ "summary": "Missing Authorization header",
22979
+ "value": {
22980
+ "error": {
22981
+ "code": "AUTH_REQUIRED",
22982
+ "message": "missing bearer token"
22983
+ }
22984
+ }
22985
+ }
22986
+ }
22987
+ }
22988
+ }
22989
+ },
22990
+ "403": {
22991
+ "description": "The caller is authenticated but not permitted to perform this operation on the target resource.",
22992
+ "content": {
22993
+ "application/json": {
22994
+ "schema": {
22995
+ "type": "object",
22996
+ "properties": {
22997
+ "error": {
22998
+ "type": "object",
22999
+ "properties": {
23000
+ "code": {
23001
+ "type": "string"
23002
+ },
23003
+ "message": {
23004
+ "type": "string"
23005
+ },
23006
+ "extra": {
23007
+ "type": "object",
23008
+ "additionalProperties": {}
23009
+ }
23010
+ },
23011
+ "required": [
23012
+ "code",
23013
+ "message"
23014
+ ]
23015
+ }
23016
+ },
23017
+ "required": [
23018
+ "error"
23019
+ ]
23020
+ },
23021
+ "examples": {
23022
+ "forbidden": {
23023
+ "summary": "Caller does not own the resource",
23024
+ "value": {
23025
+ "error": {
23026
+ "code": "FORBIDDEN",
23027
+ "message": "not allowed"
23028
+ }
23029
+ }
23030
+ }
23031
+ }
23032
+ }
23033
+ }
23034
+ },
23035
+ "404": {
23036
+ "description": "The target resource does not exist or is not visible to the caller. Soft-deleted resources are treated as not found unless an `include_deleted` flag is set.",
23037
+ "content": {
23038
+ "application/json": {
23039
+ "schema": {
23040
+ "type": "object",
23041
+ "properties": {
23042
+ "error": {
23043
+ "type": "object",
23044
+ "properties": {
23045
+ "code": {
23046
+ "type": "string"
23047
+ },
23048
+ "message": {
23049
+ "type": "string"
23050
+ },
23051
+ "extra": {
23052
+ "type": "object",
23053
+ "additionalProperties": {}
23054
+ }
23055
+ },
23056
+ "required": [
23057
+ "code",
23058
+ "message"
23059
+ ]
23060
+ }
23061
+ },
23062
+ "required": [
23063
+ "error"
23064
+ ]
23065
+ },
23066
+ "examples": {
23067
+ "notFound": {
23068
+ "summary": "Resource id is unknown to the service",
23069
+ "value": {
23070
+ "error": {
23071
+ "code": "NOT_FOUND",
23072
+ "message": "todo not found"
23073
+ }
23074
+ }
23075
+ }
23076
+ }
23077
+ }
23078
+ }
23079
+ },
23080
+ "409": {
23081
+ "description": "Optimistic-lock conflict. The supplied `expected_version` does not match the server's current version. Refetch the resource and retry.",
23082
+ "content": {
23083
+ "application/json": {
23084
+ "schema": {
23085
+ "type": "object",
23086
+ "properties": {
23087
+ "error": {
23088
+ "type": "object",
23089
+ "properties": {
23090
+ "code": {
23091
+ "type": "string"
23092
+ },
23093
+ "message": {
23094
+ "type": "string"
23095
+ },
23096
+ "extra": {
23097
+ "type": "object",
23098
+ "additionalProperties": {}
23099
+ }
23100
+ },
23101
+ "required": [
23102
+ "code",
23103
+ "message"
23104
+ ]
23105
+ }
23106
+ },
23107
+ "required": [
23108
+ "error"
23109
+ ]
23110
+ },
23111
+ "examples": {
23112
+ "versionConflict": {
23113
+ "summary": "expected_version does not match server version",
23114
+ "value": {
23115
+ "error": {
23116
+ "code": "VERSION_CONFLICT",
23117
+ "message": "expected_version 3 but current is 4",
23118
+ "extra": {
23119
+ "expected_version": 3,
23120
+ "actual_version": 4
23121
+ }
23122
+ }
23123
+ }
23124
+ }
23125
+ }
23126
+ }
23127
+ }
23128
+ },
23129
+ "429": {
23130
+ "description": "Rate limit exceeded. Retry after the duration in `error.extra.retry_after_seconds`. `limit_kind` identifies which bucket was exhausted.",
23131
+ "content": {
23132
+ "application/json": {
23133
+ "schema": {
23134
+ "type": "object",
23135
+ "properties": {
23136
+ "error": {
23137
+ "type": "object",
23138
+ "properties": {
23139
+ "code": {
23140
+ "type": "string"
23141
+ },
23142
+ "message": {
23143
+ "type": "string"
23144
+ },
23145
+ "extra": {
23146
+ "type": "object",
23147
+ "additionalProperties": {}
23148
+ }
23149
+ },
23150
+ "required": [
23151
+ "code",
23152
+ "message"
23153
+ ]
23154
+ }
23155
+ },
23156
+ "required": [
23157
+ "error"
23158
+ ]
23159
+ },
23160
+ "examples": {
23161
+ "rateLimited": {
23162
+ "summary": "Per-key rate limit hit",
23163
+ "value": {
23164
+ "error": {
23165
+ "code": "RATE_LIMITED",
23166
+ "message": "rate limit exceeded",
23167
+ "extra": {
23168
+ "retry_after_seconds": 60,
23169
+ "limit_kind": "authenticated_per_key"
23170
+ }
23171
+ }
23172
+ }
23173
+ }
23174
+ }
23175
+ }
23176
+ }
23177
+ },
23178
+ "500": {
23179
+ "description": "Unhandled server error. The request was well-formed but the service failed unexpectedly. Safe to retry idempotent operations.",
23180
+ "content": {
23181
+ "application/json": {
23182
+ "schema": {
23183
+ "type": "object",
23184
+ "properties": {
23185
+ "error": {
23186
+ "type": "object",
23187
+ "properties": {
23188
+ "code": {
23189
+ "type": "string"
23190
+ },
23191
+ "message": {
23192
+ "type": "string"
23193
+ },
23194
+ "extra": {
23195
+ "type": "object",
23196
+ "additionalProperties": {}
23197
+ }
23198
+ },
23199
+ "required": [
23200
+ "code",
23201
+ "message"
23202
+ ]
23203
+ }
23204
+ },
23205
+ "required": [
23206
+ "error"
23207
+ ]
23208
+ },
23209
+ "examples": {
23210
+ "internalError": {
23211
+ "summary": "Unhandled exception",
23212
+ "value": {
23213
+ "error": {
23214
+ "code": "INTERNAL_ERROR",
23215
+ "message": "internal error"
23216
+ }
23217
+ }
23218
+ }
23219
+ }
23220
+ }
23221
+ }
23222
+ }
23223
+ }
23224
+ }
23225
+ },
23226
+ "/todo/types": {
23227
+ "post": {
23228
+ "operationId": "todo_type_create",
23229
+ "tags": [
23230
+ "TodoTypes"
23231
+ ],
23232
+ "x-cli": {
23233
+ "command": "_internal",
23234
+ "hidden": true
23235
+ },
23236
+ "summary": "Create a todo type",
23237
+ "description": "### 🎯 Overview & Purpose\nCreate a new custom todo type. This allows you to define specialized category schemas (e.g. \"Bug Report\") and configure custom field constraints.\n\n### 🔍 When to Use\n* Use this to set up customized task behaviors (e.g. tracking choices, additional metadata, or enforcing hidden fields) tailored to a project.\n\n### 💡 Key Features & Constraints\n* **Automatic Seeding**: The first project initialization will lazily seed a `Default Project` and a `Default` todo type if they do not already exist.\n* **Metadata Schema**: Custom field keys mapped here are evaluated during task creation/update.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if required fields are missing or schema constraints are violated.",
23238
+ "security": [
23239
+ {
23240
+ "bearerAuth": []
23241
+ }
23242
+ ],
23243
+ "x-codeSamples": [
23244
+ {
23245
+ "lang": "shell",
23246
+ "label": "curl",
23247
+ "source": "curl -X POST https://api.wspc.ai/todo/types -H \"Authorization: Bearer $WSPC_API_KEY\" -H \"Content-Type: application/json\" -d '{\"label\":\"Task\"}'"
23248
+ },
23249
+ {
23250
+ "lang": "bash",
23251
+ "label": "wspc CLI",
23252
+ "source": "wspc todo types create \"Task\""
23253
+ }
23254
+ ],
23255
+ "requestBody": {
23256
+ "content": {
23257
+ "application/json": {
23258
+ "schema": {
23259
+ "$ref": "#/components/schemas/CreateTodoTypeBody"
23260
+ }
23261
+ }
23262
+ }
23263
+ },
23264
+ "responses": {
23265
+ "201": {
23266
+ "description": "Created",
23267
+ "content": {
23268
+ "application/json": {
23269
+ "schema": {
23270
+ "$ref": "#/components/schemas/TodoType"
23271
+ }
23272
+ }
23273
+ }
23274
+ },
23275
+ "400": {
23276
+ "description": "Request validation failed. The body, query, or path parameters did not match the operation's schema.",
23277
+ "content": {
23278
+ "application/json": {
23279
+ "schema": {
23280
+ "type": "object",
23281
+ "properties": {
23282
+ "error": {
23283
+ "type": "object",
23284
+ "properties": {
23285
+ "code": {
23286
+ "type": "string"
23287
+ },
23288
+ "message": {
23289
+ "type": "string"
23290
+ },
23291
+ "extra": {
23292
+ "type": "object",
23293
+ "additionalProperties": {}
23294
+ }
23295
+ },
23296
+ "required": [
23297
+ "code",
23298
+ "message"
23299
+ ]
23300
+ }
23301
+ },
23302
+ "required": [
23303
+ "error"
23304
+ ]
23305
+ },
23306
+ "examples": {
23307
+ "validationError": {
23308
+ "summary": "Body failed schema validation",
23309
+ "value": {
23310
+ "error": {
23311
+ "code": "VALIDATION_ERROR",
23312
+ "message": "title must not be empty"
23313
+ }
23314
+ }
23315
+ }
23316
+ }
23317
+ }
23318
+ }
23319
+ },
23320
+ "401": {
23321
+ "description": "Authentication is required but missing or invalid. The Bearer token (API key or OAuth access token) was absent, malformed, or rejected.",
23322
+ "content": {
23323
+ "application/json": {
23324
+ "schema": {
23325
+ "type": "object",
23326
+ "properties": {
23327
+ "error": {
23328
+ "type": "object",
23329
+ "properties": {
23330
+ "code": {
23331
+ "type": "string"
23332
+ },
23333
+ "message": {
23334
+ "type": "string"
23335
+ },
23336
+ "extra": {
23337
+ "type": "object",
23338
+ "additionalProperties": {}
23339
+ }
23340
+ },
23341
+ "required": [
23342
+ "code",
23343
+ "message"
23344
+ ]
23345
+ }
23346
+ },
23347
+ "required": [
23348
+ "error"
23349
+ ]
23350
+ },
23351
+ "examples": {
23352
+ "authRequired": {
23353
+ "summary": "Missing Authorization header",
23354
+ "value": {
23355
+ "error": {
23356
+ "code": "AUTH_REQUIRED",
23357
+ "message": "missing bearer token"
23358
+ }
23359
+ }
23360
+ }
23361
+ }
23362
+ }
23363
+ }
23364
+ },
23365
+ "403": {
23366
+ "description": "The caller is authenticated but not permitted to perform this operation on the target resource.",
23367
+ "content": {
23368
+ "application/json": {
23369
+ "schema": {
23370
+ "type": "object",
23371
+ "properties": {
23372
+ "error": {
23373
+ "type": "object",
23374
+ "properties": {
23375
+ "code": {
23376
+ "type": "string"
23377
+ },
23378
+ "message": {
23379
+ "type": "string"
23380
+ },
23381
+ "extra": {
23382
+ "type": "object",
23383
+ "additionalProperties": {}
23384
+ }
23385
+ },
23386
+ "required": [
23387
+ "code",
23388
+ "message"
23389
+ ]
23390
+ }
23391
+ },
23392
+ "required": [
23393
+ "error"
23394
+ ]
23395
+ },
23396
+ "examples": {
23397
+ "forbidden": {
23398
+ "summary": "Caller does not own the resource",
23399
+ "value": {
23400
+ "error": {
23401
+ "code": "FORBIDDEN",
23402
+ "message": "not allowed"
23403
+ }
23404
+ }
23405
+ }
23406
+ }
23407
+ }
23408
+ }
23409
+ },
23410
+ "404": {
23411
+ "description": "The target resource does not exist or is not visible to the caller. Soft-deleted resources are treated as not found unless an `include_deleted` flag is set.",
23412
+ "content": {
23413
+ "application/json": {
23414
+ "schema": {
23415
+ "type": "object",
23416
+ "properties": {
23417
+ "error": {
23418
+ "type": "object",
23419
+ "properties": {
23420
+ "code": {
23421
+ "type": "string"
23422
+ },
23423
+ "message": {
23424
+ "type": "string"
23425
+ },
23426
+ "extra": {
23427
+ "type": "object",
23428
+ "additionalProperties": {}
23429
+ }
23430
+ },
23431
+ "required": [
23432
+ "code",
23433
+ "message"
23434
+ ]
23435
+ }
23436
+ },
23437
+ "required": [
23438
+ "error"
23439
+ ]
23440
+ },
23441
+ "examples": {
23442
+ "notFound": {
23443
+ "summary": "Resource id is unknown to the service",
23444
+ "value": {
23445
+ "error": {
23446
+ "code": "NOT_FOUND",
23447
+ "message": "todo not found"
23448
+ }
23449
+ }
23450
+ }
23451
+ }
23452
+ }
23453
+ }
23454
+ },
23455
+ "409": {
23456
+ "description": "Optimistic-lock conflict. The supplied `expected_version` does not match the server's current version. Refetch the resource and retry.",
23457
+ "content": {
23458
+ "application/json": {
23459
+ "schema": {
23460
+ "type": "object",
23461
+ "properties": {
23462
+ "error": {
23463
+ "type": "object",
23464
+ "properties": {
23465
+ "code": {
23466
+ "type": "string"
23467
+ },
23468
+ "message": {
23469
+ "type": "string"
23470
+ },
23471
+ "extra": {
23472
+ "type": "object",
23473
+ "additionalProperties": {}
23474
+ }
23475
+ },
23476
+ "required": [
23477
+ "code",
23478
+ "message"
23479
+ ]
23480
+ }
23481
+ },
23482
+ "required": [
23483
+ "error"
23484
+ ]
23485
+ },
23486
+ "examples": {
23487
+ "versionConflict": {
23488
+ "summary": "expected_version does not match server version",
23489
+ "value": {
23490
+ "error": {
23491
+ "code": "VERSION_CONFLICT",
23492
+ "message": "expected_version 3 but current is 4",
23493
+ "extra": {
23494
+ "expected_version": 3,
23495
+ "actual_version": 4
23496
+ }
23497
+ }
23498
+ }
23499
+ }
23500
+ }
23501
+ }
23502
+ }
23503
+ },
23504
+ "429": {
23505
+ "description": "Rate limit exceeded. Retry after the duration in `error.extra.retry_after_seconds`. `limit_kind` identifies which bucket was exhausted.",
23506
+ "content": {
23507
+ "application/json": {
23508
+ "schema": {
23509
+ "type": "object",
23510
+ "properties": {
23511
+ "error": {
23512
+ "type": "object",
23513
+ "properties": {
23514
+ "code": {
23515
+ "type": "string"
23516
+ },
23517
+ "message": {
23518
+ "type": "string"
23519
+ },
23520
+ "extra": {
23521
+ "type": "object",
23522
+ "additionalProperties": {}
23523
+ }
23524
+ },
23525
+ "required": [
23526
+ "code",
23527
+ "message"
23528
+ ]
23529
+ }
23530
+ },
23531
+ "required": [
23532
+ "error"
23533
+ ]
23534
+ },
23535
+ "examples": {
23536
+ "rateLimited": {
23537
+ "summary": "Per-key rate limit hit",
23538
+ "value": {
23539
+ "error": {
23540
+ "code": "RATE_LIMITED",
23541
+ "message": "rate limit exceeded",
23542
+ "extra": {
23543
+ "retry_after_seconds": 60,
23544
+ "limit_kind": "authenticated_per_key"
23545
+ }
23546
+ }
23547
+ }
23548
+ }
23549
+ }
23550
+ }
23551
+ }
23552
+ },
23553
+ "500": {
23554
+ "description": "Unhandled server error. The request was well-formed but the service failed unexpectedly. Safe to retry idempotent operations.",
23555
+ "content": {
23556
+ "application/json": {
23557
+ "schema": {
23558
+ "type": "object",
23559
+ "properties": {
23560
+ "error": {
23561
+ "type": "object",
23562
+ "properties": {
23563
+ "code": {
23564
+ "type": "string"
23565
+ },
23566
+ "message": {
23567
+ "type": "string"
23568
+ },
23569
+ "extra": {
23570
+ "type": "object",
23571
+ "additionalProperties": {}
23572
+ }
23573
+ },
23574
+ "required": [
23575
+ "code",
23576
+ "message"
23577
+ ]
23578
+ }
23579
+ },
23580
+ "required": [
23581
+ "error"
23582
+ ]
23583
+ },
23584
+ "examples": {
23585
+ "internalError": {
23586
+ "summary": "Unhandled exception",
23587
+ "value": {
23588
+ "error": {
23589
+ "code": "INTERNAL_ERROR",
23590
+ "message": "internal error"
23591
+ }
23592
+ }
23593
+ }
23594
+ }
23595
+ }
23596
+ }
23597
+ }
23598
+ }
23599
+ },
23600
+ "get": {
23601
+ "operationId": "todo_type_list",
23602
+ "tags": [
23603
+ "TodoTypes"
23604
+ ],
23605
+ "x-cli": {
23606
+ "command": "todo type ls",
23607
+ "examples": [
23608
+ "wspc todo type ls"
23609
+ ],
23610
+ "display": {
23611
+ "shape": "list",
23612
+ "columns": [
23613
+ "id",
23614
+ "label"
23615
+ ],
23616
+ "format": {
23617
+ "id": "id-short",
23618
+ "label": "truncate"
23619
+ },
23620
+ "emptyMessage": "no todo types"
23621
+ }
23622
+ },
23623
+ "summary": "List todo types",
23624
+ "description": "### 🎯 Overview & Purpose\nList custom todo types defined within a project.\n\n### 🔍 When to Use\n* Use this to populate task type selection dropdown elements or load category metadata for dynamic custom forms.\n\n### 💡 Key Features & Constraints\n* **Required Parameter**: The `project_id` filter is strictly required and must match an active project.\n* **Exclusion**: Soft-deleted types are excluded by default. Pass `include_deleted=true` to surface archived rows for a recovery UI.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if `project_id` query parameter is omitted.",
23625
+ "security": [
23626
+ {
23627
+ "bearerAuth": []
23628
+ }
23629
+ ],
23630
+ "x-codeSamples": [
23631
+ {
23632
+ "lang": "shell",
23633
+ "label": "curl",
23634
+ "source": "curl https://api.wspc.ai/todo/types -H \"Authorization: Bearer $WSPC_API_KEY\""
23635
+ },
23636
+ {
23637
+ "lang": "bash",
23638
+ "label": "wspc CLI",
23639
+ "source": "wspc todo types ls"
23640
+ }
23641
+ ],
23642
+ "parameters": [
23643
+ {
23644
+ "schema": {
23645
+ "type": "string",
23646
+ "minLength": 1,
23647
+ "description": "Project id filter. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND."
23648
+ },
23649
+ "required": true,
23650
+ "description": "Project id filter. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.",
23651
+ "name": "project_id",
23652
+ "in": "query"
23653
+ },
23654
+ {
23655
+ "schema": {
23656
+ "type": "string",
23657
+ "minLength": 1
23658
+ },
23659
+ "required": false,
23660
+ "name": "user_id",
23661
+ "in": "query"
23662
+ },
23663
+ {
23664
+ "schema": {
23665
+ "type": "string"
23666
+ },
23667
+ "required": false,
23668
+ "name": "include_deleted",
23669
+ "in": "query"
23670
+ }
23671
+ ],
23672
+ "responses": {
23673
+ "200": {
23674
+ "description": "List",
23675
+ "content": {
23676
+ "application/json": {
23677
+ "schema": {
23678
+ "type": "object",
23679
+ "properties": {
23680
+ "types": {
23681
+ "type": "array",
23682
+ "items": {
23683
+ "$ref": "#/components/schemas/TodoType"
23684
+ }
23685
+ }
23686
+ },
23687
+ "required": [
23688
+ "types"
23689
+ ]
22126
23690
  }
22127
23691
  }
22128
23692
  }
@@ -22453,18 +24017,34 @@
22453
24017
  }
22454
24018
  }
22455
24019
  },
22456
- "/todo/types": {
22457
- "post": {
22458
- "operationId": "todo_type_create",
24020
+ "/todo/comments/{id}": {
24021
+ "delete": {
24022
+ "operationId": "todo_comment_delete",
22459
24023
  "tags": [
22460
- "TodoTypes"
24024
+ "Comments"
22461
24025
  ],
22462
24026
  "x-cli": {
22463
- "command": "_internal",
22464
- "hidden": true
24027
+ "command": "todo comment rm",
24028
+ "positional": [
24029
+ "id"
24030
+ ],
24031
+ "examples": [
24032
+ "wspc todo comment rm tdc_01HW3K"
24033
+ ],
24034
+ "display": {
24035
+ "shape": "object",
24036
+ "format": {
24037
+ "id": "id-short",
24038
+ "todo_id": "id-short",
24039
+ "user_id": "id-short",
24040
+ "created_at": "relative-time",
24041
+ "updated_at": "relative-time",
24042
+ "deleted_at": "relative-time"
24043
+ }
24044
+ }
22465
24045
  },
22466
- "summary": "Create a todo type",
22467
- "description": "### 🎯 Overview & Purpose\nCreate a new custom todo type. This allows you to define specialized category schemas (e.g. \"Bug Report\") and configure custom field constraints.\n\n### 🔍 When to Use\n* Use this to set up customized task behaviors (e.g. tracking choices, additional metadata, or enforcing hidden fields) tailored to a project.\n\n### 💡 Key Features & Constraints\n* **Automatic Seeding**: The first project initialization will lazily seed a `Default Project` and a `Default` todo type if they do not already exist.\n* **Metadata Schema**: Custom field keys mapped here are evaluated during task creation/update.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if required fields are missing or schema constraints are violated.",
24046
+ "summary": "Soft-delete a comment",
24047
+ "description": "### 🎯 Overview & Purpose\nSoft-delete a comment.\n\n### 💡 Key Features & Constraints\n* **Soft delete**: The comment is hidden from default listings but retained; there is no restore endpoint.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`COMMENT_NOT_FOUND` (HTTP 404)**: Thrown if the comment id is unknown, already deleted, or not in the caller's organization.",
22468
24048
  "security": [
22469
24049
  {
22470
24050
  "bearerAuth": []
@@ -22474,35 +24054,49 @@
22474
24054
  {
22475
24055
  "lang": "shell",
22476
24056
  "label": "curl",
22477
- "source": "curl -X POST https://api.wspc.ai/todo/types -H \"Authorization: Bearer $WSPC_API_KEY\" -H \"Content-Type: application/json\" -d '{\"label\":\"Task\"}'"
24057
+ "source": "curl -X DELETE https://api.wspc.ai/todo/comments/tdc_01HW3K -H \"Authorization: Bearer $WSPC_API_KEY\""
22478
24058
  },
22479
24059
  {
22480
24060
  "lang": "bash",
22481
24061
  "label": "wspc CLI",
22482
- "source": "wspc todo types create \"Task\""
22483
- },
22484
- {
22485
- "lang": "typescript",
22486
- "label": "@wspc/client",
22487
- "source": "await todo.types.create({ label: \"Task\" })"
24062
+ "source": "wspc todo comment rm tdc_01HW3K"
22488
24063
  }
22489
24064
  ],
22490
- "requestBody": {
22491
- "content": {
22492
- "application/json": {
22493
- "schema": {
22494
- "$ref": "#/components/schemas/CreateTodoTypeBody"
22495
- }
22496
- }
24065
+ "parameters": [
24066
+ {
24067
+ "schema": {
24068
+ "type": "string",
24069
+ "description": "Comment id (`tdc_<ULID>`).",
24070
+ "example": "tdc_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
24071
+ },
24072
+ "required": true,
24073
+ "description": "Comment id (`tdc_<ULID>`).",
24074
+ "name": "id",
24075
+ "in": "path"
22497
24076
  }
22498
- },
24077
+ ],
22499
24078
  "responses": {
22500
- "201": {
22501
- "description": "Created",
24079
+ "200": {
24080
+ "description": "Soft-deleted",
22502
24081
  "content": {
22503
24082
  "application/json": {
22504
24083
  "schema": {
22505
- "$ref": "#/components/schemas/TodoType"
24084
+ "$ref": "#/components/schemas/Comment"
24085
+ },
24086
+ "examples": {
24087
+ "softDeleted": {
24088
+ "summary": "Soft-deleted comment",
24089
+ "value": {
24090
+ "id": "tdc_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
24091
+ "todo_id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
24092
+ "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
24093
+ "org_id": "org_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
24094
+ "content": "Verified on staging, moving on.",
24095
+ "created_at": 1748736000000,
24096
+ "updated_at": 1748736000000,
24097
+ "deleted_at": 1748739600000
24098
+ }
24099
+ }
22506
24100
  }
22507
24101
  }
22508
24102
  }
@@ -22832,31 +24426,34 @@
22832
24426
  }
22833
24427
  }
22834
24428
  },
22835
- "get": {
22836
- "operationId": "todo_type_list",
24429
+ "patch": {
24430
+ "operationId": "todo_comment_update",
22837
24431
  "tags": [
22838
- "TodoTypes"
24432
+ "Comments"
22839
24433
  ],
22840
24434
  "x-cli": {
22841
- "command": "todo type ls",
24435
+ "command": "todo comment edit",
24436
+ "positional": [
24437
+ "id",
24438
+ "content"
24439
+ ],
22842
24440
  "examples": [
22843
- "wspc todo type ls"
24441
+ "wspc todo comment edit tdc_01HW3K \"Edited note\""
22844
24442
  ],
22845
24443
  "display": {
22846
- "shape": "list",
22847
- "columns": [
22848
- "id",
22849
- "label"
22850
- ],
24444
+ "shape": "object",
22851
24445
  "format": {
22852
24446
  "id": "id-short",
22853
- "label": "truncate"
22854
- },
22855
- "emptyMessage": "no todo types"
24447
+ "todo_id": "id-short",
24448
+ "user_id": "id-short",
24449
+ "created_at": "relative-time",
24450
+ "updated_at": "relative-time",
24451
+ "deleted_at": "relative-time"
24452
+ }
22856
24453
  }
22857
24454
  },
22858
- "summary": "List todo types",
22859
- "description": "### 🎯 Overview & Purpose\nList custom todo types defined within a project.\n\n### 🔍 When to Use\n* Use this to populate task type selection dropdown elements or load category metadata for dynamic custom forms.\n\n### 💡 Key Features & Constraints\n* **Required Parameter**: The `project_id` filter is strictly required and must match an active project.\n* **Exclusion**: Soft-deleted types are excluded by default. Pass `include_deleted=true` to surface archived rows for a recovery UI.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if `project_id` query parameter is omitted.",
24455
+ "summary": "Edit a comment",
24456
+ "description": "### 🎯 Overview & Purpose\nEdit the body of an existing comment.\n\n### 💡 Key Features & Constraints\n* **Last write wins**: There is no optimistic-lock version on comments; the latest edit replaces the content.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`COMMENT_NOT_FOUND` (HTTP 404)**: Thrown if the comment id is unknown, soft-deleted, or not in the caller's organization.\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if content is empty or exceeds 10000 characters.",
22860
24457
  "security": [
22861
24458
  {
22862
24459
  "bearerAuth": []
@@ -22866,67 +24463,65 @@
22866
24463
  {
22867
24464
  "lang": "shell",
22868
24465
  "label": "curl",
22869
- "source": "curl https://api.wspc.ai/todo/types -H \"Authorization: Bearer $WSPC_API_KEY\""
24466
+ "source": "curl -X PATCH https://api.wspc.ai/todo/comments/tdc_01HW3K -H \"Authorization: Bearer $WSPC_API_KEY\" -H \"Content-Type: application/json\" -d '{\"content\":\"Edited\"}'"
22870
24467
  },
22871
24468
  {
22872
24469
  "lang": "bash",
22873
24470
  "label": "wspc CLI",
22874
- "source": "wspc todo types ls"
22875
- },
22876
- {
22877
- "lang": "typescript",
22878
- "label": "@wspc/client",
22879
- "source": "await todo.types.list()"
24471
+ "source": "wspc todo comment edit tdc_01HW3K \"Edited\""
22880
24472
  }
22881
24473
  ],
22882
24474
  "parameters": [
22883
24475
  {
22884
24476
  "schema": {
22885
24477
  "type": "string",
22886
- "minLength": 1,
22887
- "description": "Project id filter. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND."
24478
+ "description": "Comment id (`tdc_<ULID>`).",
24479
+ "example": "tdc_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
22888
24480
  },
22889
24481
  "required": true,
22890
- "description": "Project id filter. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.",
22891
- "name": "project_id",
22892
- "in": "query"
22893
- },
22894
- {
22895
- "schema": {
22896
- "type": "string",
22897
- "minLength": 1
22898
- },
22899
- "required": false,
22900
- "name": "user_id",
22901
- "in": "query"
22902
- },
22903
- {
22904
- "schema": {
22905
- "type": "string"
22906
- },
22907
- "required": false,
22908
- "name": "include_deleted",
22909
- "in": "query"
24482
+ "description": "Comment id (`tdc_<ULID>`).",
24483
+ "name": "id",
24484
+ "in": "path"
22910
24485
  }
22911
24486
  ],
24487
+ "requestBody": {
24488
+ "content": {
24489
+ "application/json": {
24490
+ "schema": {
24491
+ "$ref": "#/components/schemas/UpdateCommentBody"
24492
+ },
24493
+ "examples": {
24494
+ "edit": {
24495
+ "summary": "Edit body",
24496
+ "value": {
24497
+ "content": "Edited note"
24498
+ }
24499
+ }
24500
+ }
24501
+ }
24502
+ }
24503
+ },
22912
24504
  "responses": {
22913
24505
  "200": {
22914
- "description": "List",
24506
+ "description": "Updated",
22915
24507
  "content": {
22916
24508
  "application/json": {
22917
24509
  "schema": {
22918
- "type": "object",
22919
- "properties": {
22920
- "types": {
22921
- "type": "array",
22922
- "items": {
22923
- "$ref": "#/components/schemas/TodoType"
22924
- }
24510
+ "$ref": "#/components/schemas/Comment"
24511
+ },
24512
+ "examples": {
24513
+ "happyPath": {
24514
+ "summary": "Active comment",
24515
+ "value": {
24516
+ "id": "tdc_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
24517
+ "todo_id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
24518
+ "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
24519
+ "org_id": "org_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
24520
+ "content": "Verified on staging, moving on.",
24521
+ "created_at": 1748736000000,
24522
+ "updated_at": 1748736000000
22925
24523
  }
22926
- },
22927
- "required": [
22928
- "types"
22929
- ]
24524
+ }
22930
24525
  }
22931
24526
  }
22932
24527
  }
@@ -23284,11 +24879,6 @@
23284
24879
  "lang": "bash",
23285
24880
  "label": "wspc CLI",
23286
24881
  "source": "wspc project rm prj_01HW3K"
23287
- },
23288
- {
23289
- "lang": "typescript",
23290
- "label": "@wspc/client",
23291
- "source": "await todo.projects.delete(\"prj_01HW3K\")"
23292
24882
  }
23293
24883
  ],
23294
24884
  "parameters": [
@@ -23682,11 +25272,6 @@
23682
25272
  "lang": "bash",
23683
25273
  "label": "wspc CLI",
23684
25274
  "source": "wspc project show prj_01HW3K"
23685
- },
23686
- {
23687
- "lang": "typescript",
23688
- "label": "@wspc/client",
23689
- "source": "await todo.projects.get(\"prj_01HW3K\")"
23690
25275
  }
23691
25276
  ],
23692
25277
  "parameters": [
@@ -24079,11 +25664,6 @@
24079
25664
  "lang": "bash",
24080
25665
  "label": "wspc CLI",
24081
25666
  "source": "wspc project update prj_01HW3K --name \"Renamed\""
24082
- },
24083
- {
24084
- "lang": "typescript",
24085
- "label": "@wspc/client",
24086
- "source": "await todo.projects.update(\"prj_01HW3K\", { name: \"Renamed\" })"
24087
25667
  }
24088
25668
  ],
24089
25669
  "parameters": [
@@ -24508,11 +26088,6 @@
24508
26088
  "lang": "bash",
24509
26089
  "label": "wspc CLI",
24510
26090
  "source": "wspc todo rrule rm tdr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
24511
- },
24512
- {
24513
- "lang": "typescript",
24514
- "label": "@wspc/client",
24515
- "source": "import { TodoClient } from \"@wspc/client\"\nconst todo = new TodoClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait todo.deleteRule(\"tdr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\")"
24516
26091
  }
24517
26092
  ],
24518
26093
  "parameters": [
@@ -24916,11 +26491,6 @@
24916
26491
  "lang": "bash",
24917
26492
  "label": "wspc CLI",
24918
26493
  "source": "wspc todo rrule show tdr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
24919
- },
24920
- {
24921
- "lang": "typescript",
24922
- "label": "@wspc/client",
24923
- "source": "import { TodoClient } from \"@wspc/client\"\nconst todo = new TodoClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait todo.getRule(\"tdr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\")"
24924
26494
  }
24925
26495
  ],
24926
26496
  "parameters": [
@@ -25325,11 +26895,6 @@
25325
26895
  "lang": "bash",
25326
26896
  "label": "wspc CLI",
25327
26897
  "source": "wspc todo rrule set tdr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F --rrule \"FREQ=WEEKLY;BYDAY=FR\""
25328
- },
25329
- {
25330
- "lang": "typescript",
25331
- "label": "@wspc/client",
25332
- "source": "import { TodoClient } from \"@wspc/client\"\nconst todo = new TodoClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait todo.updateRule(\"tdr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\", { rrule: \"FREQ=WEEKLY;BYDAY=FR\" })"
25333
26898
  }
25334
26899
  ],
25335
26900
  "parameters": [
@@ -25744,8 +27309,6 @@
25744
27309
  "project_id": "id-short",
25745
27310
  "parent_id": "id-short",
25746
27311
  "type_id": "id-short",
25747
- "title": "truncate",
25748
- "description": "truncate",
25749
27312
  "status": "status-badge",
25750
27313
  "due_at": "relative-time",
25751
27314
  "created_at": "relative-time",
@@ -25771,11 +27334,6 @@
25771
27334
  "lang": "bash",
25772
27335
  "label": "wspc CLI",
25773
27336
  "source": "wspc todo rm tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F --cascade"
25774
- },
25775
- {
25776
- "lang": "typescript",
25777
- "label": "@wspc/client",
25778
- "source": "import { TodoClient } from \"@wspc/client\"\nconst todo = new TodoClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait todo.delete(\"tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\", { cascade: true })"
25779
27337
  }
25780
27338
  ],
25781
27339
  "parameters": [
@@ -26183,14 +27741,15 @@
26183
27741
  "project_id": "id-short",
26184
27742
  "parent_id": "id-short",
26185
27743
  "type_id": "id-short",
26186
- "title": "truncate",
26187
- "description": "truncate",
26188
27744
  "status": "status-badge",
26189
27745
  "due_at": "relative-time",
26190
27746
  "created_at": "relative-time",
26191
27747
  "updated_at": "relative-time",
26192
27748
  "deleted_at": "relative-time"
26193
27749
  }
27750
+ },
27751
+ "fixedQuery": {
27752
+ "include": "children,comments"
26194
27753
  }
26195
27754
  },
26196
27755
  "summary": "Get a todo by id",
@@ -26210,11 +27769,6 @@
26210
27769
  "lang": "bash",
26211
27770
  "label": "wspc CLI",
26212
27771
  "source": "wspc todo show tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
26213
- },
26214
- {
26215
- "lang": "typescript",
26216
- "label": "@wspc/client",
26217
- "source": "import { TodoClient } from \"@wspc/client\"\nconst todo = new TodoClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait todo.get(\"tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\")"
26218
27772
  }
26219
27773
  ],
26220
27774
  "parameters": [
@@ -26261,19 +27815,27 @@
26261
27815
  "required": false,
26262
27816
  "name": "include_orphan_fields",
26263
27817
  "in": "query"
27818
+ },
27819
+ {
27820
+ "schema": {
27821
+ "type": "string"
27822
+ },
27823
+ "required": false,
27824
+ "name": "include",
27825
+ "in": "query"
26264
27826
  }
26265
27827
  ],
26266
27828
  "responses": {
26267
27829
  "200": {
26268
- "description": "The requested todo. Includes `deleted_at` only when fetched with `include_deleted=true` on a soft-deleted row.",
27830
+ "description": "The requested todo. Includes `children` (first-level) when `include=children`, `comments` when `include=comments`, and `deleted_at` only when fetched with `include_deleted=true` on a soft-deleted row.",
26269
27831
  "content": {
26270
27832
  "application/json": {
26271
27833
  "schema": {
26272
- "$ref": "#/components/schemas/Todo"
27834
+ "$ref": "#/components/schemas/TodoWithRelations"
26273
27835
  },
26274
27836
  "examples": {
26275
27837
  "happyPath": {
26276
- "summary": "Active todo with a due date",
27838
+ "summary": "Todo with first-level children and comments expanded",
26277
27839
  "value": {
26278
27840
  "id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
26279
27841
  "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
@@ -26282,11 +27844,38 @@
26282
27844
  "description": "Use refundable rate",
26283
27845
  "status": "open",
26284
27846
  "parent_id": null,
26285
- "child_count": 0,
27847
+ "child_count": 1,
26286
27848
  "version": 1,
26287
27849
  "created_at": 1748736000000,
26288
27850
  "updated_at": 1748736000000,
26289
- "due_at": "2026-06-01"
27851
+ "due_at": "2026-06-01",
27852
+ "children": [
27853
+ {
27854
+ "id": "tod_child",
27855
+ "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
27856
+ "project_id": "prj_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
27857
+ "title": "Buy milk",
27858
+ "description": "Use refundable rate",
27859
+ "status": "open",
27860
+ "parent_id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
27861
+ "child_count": 0,
27862
+ "version": 1,
27863
+ "created_at": 1748736000000,
27864
+ "updated_at": 1748736000000,
27865
+ "due_at": "2026-06-01"
27866
+ }
27867
+ ],
27868
+ "comments": [
27869
+ {
27870
+ "id": "tdc_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
27871
+ "todo_id": "tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
27872
+ "user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
27873
+ "org_id": "org_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
27874
+ "content": "Looks good",
27875
+ "created_at": 1748736000000,
27876
+ "updated_at": 1748736000000
27877
+ }
27878
+ ]
26290
27879
  }
26291
27880
  }
26292
27881
  }
@@ -26640,8 +28229,6 @@
26640
28229
  "project_id": "id-short",
26641
28230
  "parent_id": "id-short",
26642
28231
  "type_id": "id-short",
26643
- "title": "truncate",
26644
- "description": "truncate",
26645
28232
  "status": "status-badge",
26646
28233
  "due_at": "relative-time",
26647
28234
  "created_at": "relative-time",
@@ -26667,11 +28254,6 @@
26667
28254
  "lang": "bash",
26668
28255
  "label": "wspc CLI",
26669
28256
  "source": "wspc todo done tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
26670
- },
26671
- {
26672
- "lang": "typescript",
26673
- "label": "@wspc/client",
26674
- "source": "import { TodoClient } from \"@wspc/client\"\nconst todo = new TodoClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait todo.update(\"tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\", { status: \"done\" })"
26675
28257
  }
26676
28258
  ],
26677
28259
  "parameters": [
@@ -27101,11 +28683,6 @@
27101
28683
  "lang": "bash",
27102
28684
  "label": "wspc CLI",
27103
28685
  "source": "wspc todo types rm typ_01HW3K"
27104
- },
27105
- {
27106
- "lang": "typescript",
27107
- "label": "@wspc/client",
27108
- "source": "await todo.types.delete(\"typ_01HW3K\")"
27109
28686
  }
27110
28687
  ],
27111
28688
  "parameters": [
@@ -27480,11 +29057,6 @@
27480
29057
  "lang": "bash",
27481
29058
  "label": "wspc CLI",
27482
29059
  "source": "wspc todo types show typ_01HW3K"
27483
- },
27484
- {
27485
- "lang": "typescript",
27486
- "label": "@wspc/client",
27487
- "source": "await todo.types.get(\"typ_01HW3K\")"
27488
29060
  }
27489
29061
  ],
27490
29062
  "parameters": [
@@ -27859,11 +29431,6 @@
27859
29431
  "lang": "bash",
27860
29432
  "label": "wspc CLI",
27861
29433
  "source": "wspc todo types update typ_01HW3K --label \"Renamed\""
27862
- },
27863
- {
27864
- "lang": "typescript",
27865
- "label": "@wspc/client",
27866
- "source": "await todo.types.update(\"typ_01HW3K\", { label: \"Renamed\" })"
27867
29434
  }
27868
29435
  ],
27869
29436
  "parameters": [
@@ -28244,11 +29811,6 @@
28244
29811
  "lang": "shell",
28245
29812
  "label": "curl",
28246
29813
  "source": "curl -X POST https://api.wspc.ai/todo/projects/prj_01HW3K/restore -H \"Authorization: Bearer $WSPC_API_KEY\""
28247
- },
28248
- {
28249
- "lang": "typescript",
28250
- "label": "@wspc/client",
28251
- "source": "await todo.projects.restore(\"prj_01HW3K\")"
28252
29814
  }
28253
29815
  ],
28254
29816
  "parameters": [
@@ -28638,11 +30200,6 @@
28638
30200
  "lang": "shell",
28639
30201
  "label": "curl",
28640
30202
  "source": "curl -X POST https://api.wspc.ai/todo/items/tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F/restore \\\n -H \"Authorization: Bearer $WSPC_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{}'"
28641
- },
28642
- {
28643
- "lang": "typescript",
28644
- "label": "@wspc/client",
28645
- "source": "import { TodoClient } from \"@wspc/client\"\nconst todo = new TodoClient({ baseUrl: \"https://api.wspc.ai\", apiKey: process.env.WSPC_API_KEY! })\nawait todo.restore(\"tod_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\", {})"
28646
30203
  }
28647
30204
  ],
28648
30205
  "parameters": [
@@ -29054,11 +30611,6 @@
29054
30611
  "lang": "shell",
29055
30612
  "label": "curl",
29056
30613
  "source": "curl -X POST https://api.wspc.ai/todo/types/typ_01HW3K/restore -H \"Authorization: Bearer $WSPC_API_KEY\""
29057
- },
29058
- {
29059
- "lang": "typescript",
29060
- "label": "@wspc/client",
29061
- "source": "await todo.types.restore(\"typ_01HW3K\")"
29062
30614
  }
29063
30615
  ],
29064
30616
  "parameters": [
@@ -29415,6 +30967,10 @@
29415
30967
  "name": "Auth",
29416
30968
  "description": "Email magic-code login: request code, verify code, current user."
29417
30969
  },
30970
+ {
30971
+ "name": "Comments",
30972
+ "description": "Comments endpoints."
30973
+ },
29418
30974
  {
29419
30975
  "name": "EmailAliases",
29420
30976
  "description": "User-managed @wspc.app email aliases that route inbound mail to the user's inbox."