atris 2.2.2 → 2.3.1
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/atris/skills/calendar/SKILL.md +3 -3
- package/atris/skills/email-agent/SKILL.md +42 -2
- package/atris/skills/notion/SKILL.md +478 -0
- package/atris/skills/slides/SKILL.md +355 -0
- package/bin/atris.js +35 -109
- package/commands/auth.js +97 -2
- package/commands/integrations.js +26 -12
- package/commands/plugin.js +450 -0
- package/commands/sync.js +87 -1
- package/package.json +1 -1
- package/utils/auth.js +72 -3
- package/utils/update-check.js +33 -0
|
@@ -144,12 +144,12 @@ curl -s -X POST "https://api.atris.ai/api/integrations/google-calendar/events" \
|
|
|
144
144
|
-H "Authorization: Bearer $TOKEN" \
|
|
145
145
|
-H "Content-Type: application/json" \
|
|
146
146
|
-d '{
|
|
147
|
-
"summary": "Meeting with
|
|
147
|
+
"summary": "Meeting with Hugo",
|
|
148
148
|
"start": "2026-02-15T14:00:00-08:00",
|
|
149
149
|
"end": "2026-02-15T15:00:00-08:00",
|
|
150
|
-
"description": "Discuss
|
|
150
|
+
"description": "Discuss project roadmap",
|
|
151
151
|
"location": "Zoom",
|
|
152
|
-
"attendees": ["
|
|
152
|
+
"attendees": ["hugo@atrismail.com"],
|
|
153
153
|
"timezone": "America/Los_Angeles"
|
|
154
154
|
}'
|
|
155
155
|
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: email-agent
|
|
3
3
|
description: Gmail integration via AtrisOS API. Read, send, archive emails. Use when user asks about email, inbox, or wants to send/check messages.
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
tags:
|
|
6
6
|
- email-agent
|
|
7
7
|
- backend
|
|
@@ -158,6 +158,33 @@ curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send" \
|
|
|
158
158
|
}'
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
+
**Reply in thread (IMPORTANT — use this for all replies):**
|
|
162
|
+
|
|
163
|
+
To reply within an existing email thread, you MUST pass `thread_id` and `reply_to_message_id`. Without these, Gmail creates a new thread.
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
# 1. First, get the message you're replying to (extract thread_id and id)
|
|
167
|
+
curl -s "https://api.atris.ai/api/integrations/gmail/messages/{message_id}" \
|
|
168
|
+
-H "Authorization: Bearer $TOKEN"
|
|
169
|
+
# Response includes: id, thread_id, subject, from, etc.
|
|
170
|
+
|
|
171
|
+
# 2. Send reply in the same thread
|
|
172
|
+
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send" \
|
|
173
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
174
|
+
-H "Content-Type: application/json" \
|
|
175
|
+
-d '{
|
|
176
|
+
"to": "original-sender@example.com",
|
|
177
|
+
"subject": "Re: Original Subject",
|
|
178
|
+
"body": "Your reply text here",
|
|
179
|
+
"thread_id": "THREAD_ID_FROM_STEP_1",
|
|
180
|
+
"reply_to_message_id": "MESSAGE_ID_FROM_STEP_1"
|
|
181
|
+
}'
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
- `thread_id` — The thread ID from the original message. Tells Gmail which thread to add this to.
|
|
185
|
+
- `reply_to_message_id` — The message ID you're replying to. The backend uses this to set `In-Reply-To` and `References` headers so Gmail threads it correctly.
|
|
186
|
+
- `subject` — Must match the original subject with "Re: " prefix.
|
|
187
|
+
|
|
161
188
|
**With attachments:**
|
|
162
189
|
```bash
|
|
163
190
|
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send" \
|
|
@@ -264,6 +291,14 @@ curl -s -X DELETE "https://api.atris.ai/api/integrations/gmail" \
|
|
|
264
291
|
4. On approval: `POST /send` with `{to, subject, body}`
|
|
265
292
|
5. Confirm: "Email sent!"
|
|
266
293
|
|
|
294
|
+
### "Reply to this email"
|
|
295
|
+
1. Run bootstrap
|
|
296
|
+
2. Read the message: `GET /messages/{message_id}` — extract `id`, `thread_id`, `from`, `subject`
|
|
297
|
+
3. Draft reply content
|
|
298
|
+
4. **Show user the reply for approval**
|
|
299
|
+
5. On approval: `POST /send` with `{to, subject: "Re: ...", body, thread_id, reply_to_message_id}`
|
|
300
|
+
6. Verify: response `thread_id` matches original thread_id (if it doesn't, something went wrong)
|
|
301
|
+
|
|
267
302
|
### "Clean up my inbox"
|
|
268
303
|
1. Run bootstrap
|
|
269
304
|
2. List: `GET /messages?query=in:inbox&max_results=50`
|
|
@@ -357,11 +392,16 @@ curl -s "https://api.atris.ai/api/integrations/gmail/status" -H "Authorization:
|
|
|
357
392
|
# List inbox
|
|
358
393
|
curl -s "https://api.atris.ai/api/integrations/gmail/messages?query=in:inbox&max_results=10" -H "Authorization: Bearer $TOKEN"
|
|
359
394
|
|
|
360
|
-
# Send email
|
|
395
|
+
# Send new email
|
|
361
396
|
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send" \
|
|
362
397
|
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
363
398
|
-d '{"to":"email@example.com","subject":"Hi","body":"Hello!"}'
|
|
364
399
|
|
|
400
|
+
# Reply in thread (pass thread_id + reply_to_message_id)
|
|
401
|
+
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send" \
|
|
402
|
+
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
403
|
+
-d '{"to":"sender@example.com","subject":"Re: Original","body":"Reply text","thread_id":"THREAD_ID","reply_to_message_id":"MSG_ID"}'
|
|
404
|
+
|
|
365
405
|
# List drafts
|
|
366
406
|
curl -s "https://api.atris.ai/api/integrations/gmail/drafts" -H "Authorization: Bearer $TOKEN"
|
|
367
407
|
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: notion
|
|
3
|
+
description: Notion integration via AtrisOS API. Search pages, read/create/update pages, query databases, manage blocks and comments. Use when user asks about Notion, pages, databases, wikis, or docs.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
tags:
|
|
6
|
+
- notion
|
|
7
|
+
- backend
|
|
8
|
+
- productivity
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Notion Agent
|
|
12
|
+
|
|
13
|
+
> Drop this in `~/.claude/skills/notion/SKILL.md` and Claude Code becomes your Notion assistant.
|
|
14
|
+
|
|
15
|
+
## Bootstrap (ALWAYS Run First)
|
|
16
|
+
|
|
17
|
+
Before any Notion operation, run this bootstrap to ensure everything is set up:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
#!/bin/bash
|
|
21
|
+
set -e
|
|
22
|
+
|
|
23
|
+
# 1. Check if atris CLI is installed
|
|
24
|
+
if ! command -v atris &> /dev/null; then
|
|
25
|
+
echo "Installing atris CLI..."
|
|
26
|
+
npm install -g atris
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
# 2. Check if logged in to AtrisOS
|
|
30
|
+
if [ ! -f ~/.atris/credentials.json ]; then
|
|
31
|
+
echo "Not logged in to AtrisOS."
|
|
32
|
+
echo ""
|
|
33
|
+
echo "Option 1 (interactive): Run 'atris login' and follow prompts"
|
|
34
|
+
echo "Option 2 (non-interactive): Get token from https://atris.ai/auth/cli"
|
|
35
|
+
echo " Then run: atris login --token YOUR_TOKEN"
|
|
36
|
+
echo ""
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# 3. Extract token
|
|
41
|
+
if command -v node &> /dev/null; then
|
|
42
|
+
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
|
|
43
|
+
elif command -v python3 &> /dev/null; then
|
|
44
|
+
TOKEN=$(python3 -c "import json,os; print(json.load(open(os.path.expanduser('~/.atris/credentials.json')))['token'])")
|
|
45
|
+
elif command -v jq &> /dev/null; then
|
|
46
|
+
TOKEN=$(jq -r '.token' ~/.atris/credentials.json)
|
|
47
|
+
else
|
|
48
|
+
echo "Error: Need node, python3, or jq to read credentials"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# 4. Check Notion connection status
|
|
53
|
+
STATUS=$(curl -s "https://api.atris.ai/api/integrations/notion/status" \
|
|
54
|
+
-H "Authorization: Bearer $TOKEN")
|
|
55
|
+
|
|
56
|
+
if echo "$STATUS" | grep -q "Token expired\|Not authenticated"; then
|
|
57
|
+
echo "Token expired. Please re-authenticate:"
|
|
58
|
+
echo " Run: atris login --force"
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
if command -v node &> /dev/null; then
|
|
63
|
+
CONNECTED=$(node -e "try{console.log(JSON.parse('$STATUS').connected||false)}catch(e){console.log(false)}")
|
|
64
|
+
elif command -v python3 &> /dev/null; then
|
|
65
|
+
CONNECTED=$(echo "$STATUS" | python3 -c "import sys,json; print(json.load(sys.stdin).get('connected', False))")
|
|
66
|
+
else
|
|
67
|
+
CONNECTED=$(echo "$STATUS" | jq -r '.connected // false')
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
if [ "$CONNECTED" != "true" ] && [ "$CONNECTED" != "True" ]; then
|
|
71
|
+
echo "Notion not connected. Getting authorization URL..."
|
|
72
|
+
AUTH=$(curl -s -X POST "https://api.atris.ai/api/integrations/notion/start" \
|
|
73
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
74
|
+
-H "Content-Type: application/json" \
|
|
75
|
+
-d '{"return_url":"https://atris.ai/dashboard/settings"}')
|
|
76
|
+
|
|
77
|
+
if command -v node &> /dev/null; then
|
|
78
|
+
URL=$(node -e "try{console.log(JSON.parse('$AUTH').auth_url||'')}catch(e){console.log('')}")
|
|
79
|
+
elif command -v python3 &> /dev/null; then
|
|
80
|
+
URL=$(echo "$AUTH" | python3 -c "import sys,json; print(json.load(sys.stdin).get('auth_url', ''))")
|
|
81
|
+
else
|
|
82
|
+
URL=$(echo "$AUTH" | jq -r '.auth_url // empty')
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
echo ""
|
|
86
|
+
echo "Open this URL to connect your Notion:"
|
|
87
|
+
echo "$URL"
|
|
88
|
+
echo ""
|
|
89
|
+
echo "After authorizing, run your command again."
|
|
90
|
+
exit 0
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
echo "Ready. Notion is connected."
|
|
94
|
+
export ATRIS_TOKEN="$TOKEN"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## API Reference
|
|
100
|
+
|
|
101
|
+
Base: `https://api.atris.ai/api/integrations`
|
|
102
|
+
|
|
103
|
+
All requests require: `-H "Authorization: Bearer $TOKEN"`
|
|
104
|
+
|
|
105
|
+
### Get Token (after bootstrap)
|
|
106
|
+
```bash
|
|
107
|
+
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Search
|
|
113
|
+
|
|
114
|
+
### Search Pages & Databases
|
|
115
|
+
```bash
|
|
116
|
+
curl -s "https://api.atris.ai/api/integrations/notion/search?q=meeting+notes&page_size=20" \
|
|
117
|
+
-H "Authorization: Bearer $TOKEN"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Filter by type:**
|
|
121
|
+
```bash
|
|
122
|
+
# Only pages
|
|
123
|
+
curl -s "https://api.atris.ai/api/integrations/notion/search?q=roadmap&filter_type=page" \
|
|
124
|
+
-H "Authorization: Bearer $TOKEN"
|
|
125
|
+
|
|
126
|
+
# Only databases
|
|
127
|
+
curl -s "https://api.atris.ai/api/integrations/notion/search?q=tasks&filter_type=database" \
|
|
128
|
+
-H "Authorization: Bearer $TOKEN"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Pages
|
|
134
|
+
|
|
135
|
+
### Get a Page
|
|
136
|
+
```bash
|
|
137
|
+
curl -s "https://api.atris.ai/api/integrations/notion/pages/{page_id}" \
|
|
138
|
+
-H "Authorization: Bearer $TOKEN"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Create a Page (under a page)
|
|
142
|
+
```bash
|
|
143
|
+
curl -s -X POST "https://api.atris.ai/api/integrations/notion/pages" \
|
|
144
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
145
|
+
-H "Content-Type: application/json" \
|
|
146
|
+
-d '{
|
|
147
|
+
"parent_id": "PARENT_PAGE_ID",
|
|
148
|
+
"parent_type": "page_id",
|
|
149
|
+
"title": "Meeting Notes - Feb 14"
|
|
150
|
+
}'
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Create a Page (in a database)
|
|
154
|
+
```bash
|
|
155
|
+
curl -s -X POST "https://api.atris.ai/api/integrations/notion/pages" \
|
|
156
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
157
|
+
-H "Content-Type: application/json" \
|
|
158
|
+
-d '{
|
|
159
|
+
"parent_id": "DATABASE_ID",
|
|
160
|
+
"parent_type": "database_id",
|
|
161
|
+
"title": "New Task",
|
|
162
|
+
"properties": {
|
|
163
|
+
"Status": {"select": {"name": "In Progress"}},
|
|
164
|
+
"Priority": {"select": {"name": "High"}}
|
|
165
|
+
}
|
|
166
|
+
}'
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Create a Page with Content
|
|
170
|
+
```bash
|
|
171
|
+
curl -s -X POST "https://api.atris.ai/api/integrations/notion/pages" \
|
|
172
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
173
|
+
-H "Content-Type: application/json" \
|
|
174
|
+
-d '{
|
|
175
|
+
"parent_id": "PARENT_PAGE_ID",
|
|
176
|
+
"parent_type": "page_id",
|
|
177
|
+
"title": "Project Brief",
|
|
178
|
+
"children": [
|
|
179
|
+
{
|
|
180
|
+
"object": "block",
|
|
181
|
+
"type": "heading_2",
|
|
182
|
+
"heading_2": {"rich_text": [{"type": "text", "text": {"content": "Overview"}}]}
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"object": "block",
|
|
186
|
+
"type": "paragraph",
|
|
187
|
+
"paragraph": {"rich_text": [{"type": "text", "text": {"content": "This project aims to..."}}]}
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"object": "block",
|
|
191
|
+
"type": "bulleted_list_item",
|
|
192
|
+
"bulleted_list_item": {"rich_text": [{"type": "text", "text": {"content": "Goal 1: Ship MVP"}}]}
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
}'
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Update a Page
|
|
199
|
+
```bash
|
|
200
|
+
curl -s -X PATCH "https://api.atris.ai/api/integrations/notion/pages/{page_id}" \
|
|
201
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
202
|
+
-H "Content-Type: application/json" \
|
|
203
|
+
-d '{
|
|
204
|
+
"properties": {
|
|
205
|
+
"Status": {"select": {"name": "Done"}}
|
|
206
|
+
}
|
|
207
|
+
}'
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Archive a Page
|
|
211
|
+
```bash
|
|
212
|
+
curl -s -X PATCH "https://api.atris.ai/api/integrations/notion/pages/{page_id}" \
|
|
213
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
214
|
+
-H "Content-Type: application/json" \
|
|
215
|
+
-d '{"archived": true}'
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Databases
|
|
221
|
+
|
|
222
|
+
### Get Database Schema
|
|
223
|
+
```bash
|
|
224
|
+
curl -s "https://api.atris.ai/api/integrations/notion/databases/{database_id}" \
|
|
225
|
+
-H "Authorization: Bearer $TOKEN"
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Query a Database
|
|
229
|
+
```bash
|
|
230
|
+
curl -s -X POST "https://api.atris.ai/api/integrations/notion/databases/{database_id}/query" \
|
|
231
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
232
|
+
-H "Content-Type: application/json" \
|
|
233
|
+
-d '{"page_size": 20}'
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**With filters:**
|
|
237
|
+
```bash
|
|
238
|
+
curl -s -X POST "https://api.atris.ai/api/integrations/notion/databases/{database_id}/query" \
|
|
239
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
240
|
+
-H "Content-Type: application/json" \
|
|
241
|
+
-d '{
|
|
242
|
+
"filter": {
|
|
243
|
+
"property": "Status",
|
|
244
|
+
"select": {"equals": "In Progress"}
|
|
245
|
+
},
|
|
246
|
+
"sorts": [
|
|
247
|
+
{"property": "Created", "direction": "descending"}
|
|
248
|
+
],
|
|
249
|
+
"page_size": 50
|
|
250
|
+
}'
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Create a Database
|
|
254
|
+
```bash
|
|
255
|
+
curl -s -X POST "https://api.atris.ai/api/integrations/notion/databases" \
|
|
256
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
257
|
+
-H "Content-Type: application/json" \
|
|
258
|
+
-d '{
|
|
259
|
+
"parent_page_id": "PAGE_ID",
|
|
260
|
+
"title": "Task Tracker",
|
|
261
|
+
"properties": {
|
|
262
|
+
"Name": {"title": {}},
|
|
263
|
+
"Status": {"select": {"options": [{"name": "To Do"}, {"name": "In Progress"}, {"name": "Done"}]}},
|
|
264
|
+
"Priority": {"select": {"options": [{"name": "High"}, {"name": "Medium"}, {"name": "Low"}]}},
|
|
265
|
+
"Due Date": {"date": {}}
|
|
266
|
+
}
|
|
267
|
+
}'
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Blocks (Page Content)
|
|
273
|
+
|
|
274
|
+
### Read Page Content
|
|
275
|
+
```bash
|
|
276
|
+
curl -s "https://api.atris.ai/api/integrations/notion/blocks/{page_id}/children?page_size=50" \
|
|
277
|
+
-H "Authorization: Bearer $TOKEN"
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Append Content to a Page
|
|
281
|
+
```bash
|
|
282
|
+
curl -s -X PATCH "https://api.atris.ai/api/integrations/notion/blocks/{page_id}/children" \
|
|
283
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
284
|
+
-H "Content-Type: application/json" \
|
|
285
|
+
-d '{
|
|
286
|
+
"children": [
|
|
287
|
+
{
|
|
288
|
+
"object": "block",
|
|
289
|
+
"type": "paragraph",
|
|
290
|
+
"paragraph": {"rich_text": [{"type": "text", "text": {"content": "Added via Atris!"}}]}
|
|
291
|
+
}
|
|
292
|
+
]
|
|
293
|
+
}'
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Delete a Block
|
|
297
|
+
```bash
|
|
298
|
+
curl -s -X DELETE "https://api.atris.ai/api/integrations/notion/blocks/{block_id}" \
|
|
299
|
+
-H "Authorization: Bearer $TOKEN"
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Users
|
|
305
|
+
|
|
306
|
+
### List Workspace Users
|
|
307
|
+
```bash
|
|
308
|
+
curl -s "https://api.atris.ai/api/integrations/notion/users" \
|
|
309
|
+
-H "Authorization: Bearer $TOKEN"
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Get Integration Info
|
|
313
|
+
```bash
|
|
314
|
+
curl -s "https://api.atris.ai/api/integrations/notion/me" \
|
|
315
|
+
-H "Authorization: Bearer $TOKEN"
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Comments
|
|
321
|
+
|
|
322
|
+
### Get Comments on a Page
|
|
323
|
+
```bash
|
|
324
|
+
curl -s "https://api.atris.ai/api/integrations/notion/comments/{page_id}" \
|
|
325
|
+
-H "Authorization: Bearer $TOKEN"
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Add a Comment
|
|
329
|
+
```bash
|
|
330
|
+
curl -s -X POST "https://api.atris.ai/api/integrations/notion/comments" \
|
|
331
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
332
|
+
-H "Content-Type: application/json" \
|
|
333
|
+
-d '{
|
|
334
|
+
"parent_id": "PAGE_ID",
|
|
335
|
+
"text": "This looks great! Approved."
|
|
336
|
+
}'
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Reply to a Discussion
|
|
340
|
+
```bash
|
|
341
|
+
curl -s -X POST "https://api.atris.ai/api/integrations/notion/comments" \
|
|
342
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
343
|
+
-H "Content-Type: application/json" \
|
|
344
|
+
-d '{
|
|
345
|
+
"parent_id": "PAGE_ID",
|
|
346
|
+
"text": "Thanks for the feedback!",
|
|
347
|
+
"discussion_id": "DISCUSSION_ID"
|
|
348
|
+
}'
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Workflows
|
|
354
|
+
|
|
355
|
+
### "Search my Notion for X"
|
|
356
|
+
1. Run bootstrap
|
|
357
|
+
2. Search: `GET /notion/search?q=X`
|
|
358
|
+
3. Display: title, type (page/database), last edited
|
|
359
|
+
|
|
360
|
+
### "What's in my task database?"
|
|
361
|
+
1. Run bootstrap
|
|
362
|
+
2. Search databases: `GET /notion/search?q=tasks&filter_type=database`
|
|
363
|
+
3. Query: `POST /notion/databases/{id}/query` with filters
|
|
364
|
+
4. Display rows with properties
|
|
365
|
+
|
|
366
|
+
### "Create a page with notes"
|
|
367
|
+
1. Run bootstrap
|
|
368
|
+
2. Search for parent page: `GET /notion/search?q=parent+name&filter_type=page`
|
|
369
|
+
3. Create page: `POST /notion/pages` with title + children blocks
|
|
370
|
+
4. Confirm: "Page created!" with link
|
|
371
|
+
|
|
372
|
+
### "Add a row to a database"
|
|
373
|
+
1. Run bootstrap
|
|
374
|
+
2. Get database schema: `GET /notion/databases/{id}` (to see property names/types)
|
|
375
|
+
3. Create page in database: `POST /notion/pages` with `parent_type=database_id` and matching properties
|
|
376
|
+
4. Confirm with row details
|
|
377
|
+
|
|
378
|
+
### "Read a page"
|
|
379
|
+
1. Run bootstrap
|
|
380
|
+
2. Get page metadata: `GET /notion/pages/{id}`
|
|
381
|
+
3. Get page content: `GET /notion/blocks/{id}/children`
|
|
382
|
+
4. Display title + content blocks
|
|
383
|
+
|
|
384
|
+
### "Update task status"
|
|
385
|
+
1. Run bootstrap
|
|
386
|
+
2. Find the task: search or query database
|
|
387
|
+
3. Update: `PATCH /notion/pages/{id}` with new property values
|
|
388
|
+
4. Confirm the change
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## Block Types Reference
|
|
393
|
+
|
|
394
|
+
Common block types for creating content:
|
|
395
|
+
|
|
396
|
+
| Type | Key | Rich text field |
|
|
397
|
+
|------|-----|----------------|
|
|
398
|
+
| Paragraph | `paragraph` | `rich_text` |
|
|
399
|
+
| Heading 1 | `heading_1` | `rich_text` |
|
|
400
|
+
| Heading 2 | `heading_2` | `rich_text` |
|
|
401
|
+
| Heading 3 | `heading_3` | `rich_text` |
|
|
402
|
+
| Bullet list | `bulleted_list_item` | `rich_text` |
|
|
403
|
+
| Numbered list | `numbered_list_item` | `rich_text` |
|
|
404
|
+
| To-do | `to_do` | `rich_text` + `checked` |
|
|
405
|
+
| Code | `code` | `rich_text` + `language` |
|
|
406
|
+
| Quote | `quote` | `rich_text` |
|
|
407
|
+
| Divider | `divider` | (none) |
|
|
408
|
+
| Callout | `callout` | `rich_text` + `icon` |
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## Important Notes
|
|
413
|
+
|
|
414
|
+
- **Notion tokens don't expire** — once connected, it stays connected
|
|
415
|
+
- **Page IDs**: Notion uses UUIDs like `12345678-abcd-1234-abcd-123456789abc`. You can get them from URLs or search results
|
|
416
|
+
- **Database pages**: When adding rows to a database, the "page" properties must match the database schema
|
|
417
|
+
- **Content = Blocks**: A page's visible content is a list of blocks. Use the blocks endpoint to read/write content
|
|
418
|
+
- **Search scope**: Only pages/databases shared with the Atris integration are visible
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Error Handling
|
|
423
|
+
|
|
424
|
+
| Error | Meaning | Solution |
|
|
425
|
+
|-------|---------|----------|
|
|
426
|
+
| `Token expired` | AtrisOS session expired | Run `atris login` |
|
|
427
|
+
| `Notion not connected` | OAuth not completed | Re-run bootstrap |
|
|
428
|
+
| `401 Unauthorized` | Invalid/expired token | Run `atris login` |
|
|
429
|
+
| `object_not_found` | Page/database not shared with integration | Share the page with the Atris integration in Notion |
|
|
430
|
+
| `validation_error` | Bad request format | Check property names match database schema |
|
|
431
|
+
| `restricted_resource` | No access to resource | Share with Atris integration in Notion settings |
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## Security Model
|
|
436
|
+
|
|
437
|
+
1. **Local token** (`~/.atris/credentials.json`): Your AtrisOS auth token, stored locally.
|
|
438
|
+
2. **Notion credentials**: Access token stored **server-side** in AtrisOS encrypted vault.
|
|
439
|
+
3. **Access control**: AtrisOS API enforces that you can only access your own Notion.
|
|
440
|
+
4. **Scoped access**: Only pages/databases explicitly shared with the Atris integration are accessible.
|
|
441
|
+
5. **HTTPS only**: All API communication encrypted in transit.
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## Quick Reference
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
# Setup (one time)
|
|
449
|
+
npm install -g atris && atris login
|
|
450
|
+
|
|
451
|
+
# Get token
|
|
452
|
+
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
|
|
453
|
+
|
|
454
|
+
# Check connection
|
|
455
|
+
curl -s "https://api.atris.ai/api/integrations/notion/status" -H "Authorization: Bearer $TOKEN"
|
|
456
|
+
|
|
457
|
+
# Search
|
|
458
|
+
curl -s "https://api.atris.ai/api/integrations/notion/search?q=meeting" -H "Authorization: Bearer $TOKEN"
|
|
459
|
+
|
|
460
|
+
# Read a page
|
|
461
|
+
curl -s "https://api.atris.ai/api/integrations/notion/pages/PAGE_ID" -H "Authorization: Bearer $TOKEN"
|
|
462
|
+
|
|
463
|
+
# Read page content
|
|
464
|
+
curl -s "https://api.atris.ai/api/integrations/notion/blocks/PAGE_ID/children" -H "Authorization: Bearer $TOKEN"
|
|
465
|
+
|
|
466
|
+
# Create a page
|
|
467
|
+
curl -s -X POST "https://api.atris.ai/api/integrations/notion/pages" \
|
|
468
|
+
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
469
|
+
-d '{"parent_id":"PAGE_ID","parent_type":"page_id","title":"New Page"}'
|
|
470
|
+
|
|
471
|
+
# Query a database
|
|
472
|
+
curl -s -X POST "https://api.atris.ai/api/integrations/notion/databases/DB_ID/query" \
|
|
473
|
+
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
474
|
+
-d '{"page_size":20}'
|
|
475
|
+
|
|
476
|
+
# List users
|
|
477
|
+
curl -s "https://api.atris.ai/api/integrations/notion/users" -H "Authorization: Bearer $TOKEN"
|
|
478
|
+
```
|