| name | slides |
| description | Google Slides integration via AtrisOS API. List, create, read, and update presentations. Add slides, text, shapes, images. Export to PDF. Use when user asks about slides, presentations, decks, or pitch decks. |
| version | 1.0.0 |
| tags | ["slides","google","productivity"] |
Google Slides Agent
Drop this in ~/.claude/skills/slides/SKILL.md and Claude Code becomes your presentation assistant.
Prerequisites
Google Slides shares OAuth with Google Drive. If Drive is connected, Slides works automatically. If not:
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
curl -s "https://api.atris.ai/api/integrations/google-drive/status" -H "Authorization: Bearer $TOKEN"
curl -s -X POST "https://api.atris.ai/api/integrations/google-drive/start" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"next_url":"https://atris.ai/dashboard/settings"}'
API Reference
Base: https://api.atris.ai/api/integrations/google-slides
All requests require: -H "Authorization: Bearer $TOKEN"
Get Token
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
Presentations
List Presentations
curl -s "https://api.atris.ai/api/integrations/google-slides/presentations?page_size=20" \
-H "Authorization: Bearer $TOKEN"
Get a Presentation (with all slides)
curl -s "https://api.atris.ai/api/integrations/google-slides/presentations/{presentation_id}" \
-H "Authorization: Bearer $TOKEN"
Create a Presentation
curl -s -X POST "https://api.atris.ai/api/integrations/google-slides/presentations" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"title": "Q1 2026 Review"}'
Updating Slides (batch-update)
All slide mutations use the batch-update endpoint. This is the most powerful endpoint — it can add slides, insert text, add shapes, images, change formatting, and more.
curl -s -X POST "https://api.atris.ai/api/integrations/google-slides/presentations/{id}/batch-update" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"requests": [...]}'
Add a Blank Slide
{
"requests": [
{
"createSlide": {
"insertionIndex": 1,
"slideLayoutReference": {
"predefinedLayout": "BLANK"
}
}
}
]
}
Available layouts: BLANK, TITLE, TITLE_AND_BODY, TITLE_AND_TWO_COLUMNS, TITLE_ONLY, SECTION_HEADER, SECTION_TITLE_AND_DESCRIPTION, ONE_COLUMN_TEXT, MAIN_POINT, BIG_NUMBER
Add a Title Slide
{
"requests": [
{
"createSlide": {
"insertionIndex": 0,
"slideLayoutReference": {
"predefinedLayout": "TITLE"
},
"placeholderIdMappings": [
{"layoutPlaceholder": {"type": "TITLE"}, "objectId": "titleId"},
{"layoutPlaceholder": {"type": "SUBTITLE"}, "objectId": "subtitleId"}
]
}
},
{
"insertText": {
"objectId": "titleId",
"text": "Q1 2026 Review"
}
},
{
"insertText": {
"objectId": "subtitleId",
"text": "{{company_name}} - Confidential"
}
}
]
}
Insert Text into an Element
{
"requests": [
{
"insertText": {
"objectId": "ELEMENT_ID",
"text": "Hello, world!"
}
}
]
}
Add a Text Box
{
"requests": [
{
"createShape": {
"objectId": "myTextBox1",
"shapeType": "TEXT_BOX",
"elementProperties": {
"pageObjectId": "SLIDE_ID",
"size": {
"width": {"magnitude": 400, "unit": "PT"},
"height": {"magnitude": 50, "unit": "PT"}
},
"transform": {
"scaleX": 1, "scaleY": 1,
"translateX": 100, "translateY": 200,
"unit": "PT"
}
}
}
},
{
"insertText": {
"objectId": "myTextBox1",
"text": "Custom text here"
}
}
]
}
Add an Image
{
"requests": [
{
"createImage": {
"objectId": "myImage1",
"url": "https://example.com/image.png",
"elementProperties": {
"pageObjectId": "SLIDE_ID",
"size": {
"width": {"magnitude": 300, "unit": "PT"},
"height": {"magnitude": 200, "unit": "PT"}
},
"transform": {
"scaleX": 1, "scaleY": 1,
"translateX": 150, "translateY": 100,
"unit": "PT"
}
}
}
}
]
}
Replace All Text (find & replace)
{
"requests": [
{
"replaceAllText": {
"containsText": {"text": "{{company_name}}"},
"replaceText": "Example Co"
}
}
]
}
Delete a Slide or Element
{
"requests": [
{
"deleteObject": {
"objectId": "SLIDE_OR_ELEMENT_ID"
}
}
]
}
Style Text
{
"requests": [
{
"updateTextStyle": {
"objectId": "ELEMENT_ID",
"style": {
"bold": true,
"fontSize": {"magnitude": 24, "unit": "PT"},
"foregroundColor": {
"opaqueColor": {"rgbColor": {"red": 0.2, "green": 0.2, "blue": 0.8}}
}
},
"fields": "bold,fontSize,foregroundColor"
}
}
]
}
Pages (Individual Slides)
Get a Single Slide
curl -s "https://api.atris.ai/api/integrations/google-slides/presentations/{id}/pages/{page_id}" \
-H "Authorization: Bearer $TOKEN"
Get Slide Thumbnail
curl -s "https://api.atris.ai/api/integrations/google-slides/presentations/{id}/pages/{page_id}/thumbnail" \
-H "Authorization: Bearer $TOKEN"
Export
Export as PDF
curl -s "https://api.atris.ai/api/integrations/google-slides/presentations/{id}/export" \
-H "Authorization: Bearer $TOKEN"
Returns {"pdf_base64": "...", "content_type": "application/pdf"}.
Workflows
"Create a pitch deck"
- Create presentation:
POST /presentations with title
- Get the presentation to find the first slide ID
- Batch update: add title slide, content slides, closing slide
- Each slide: createSlide + insertText for content
- Return the presentation URL:
https://docs.google.com/presentation/d/{id}
"List my presentations"
GET /presentations
- Display: name, last modified, link
"Add a slide to an existing deck"
GET /presentations/{id} to see current slides
- Batch update: createSlide at the desired index
- Add content with insertText, createShape, createImage
"Export deck to PDF"
GET /presentations/{id}/export
- Decode base64 and save to file
"Update text in a deck"
GET /presentations/{id} to find element IDs
- Batch update with replaceAllText for template variables
- Or insertText/deleteText for specific elements
Important Notes
- Shares Drive OAuth — no separate connection needed. If Drive is connected, Slides works
- Batch update is everything — all slide mutations (add, edit, delete, style) go through batch-update
- Object IDs — every slide, shape, text box, image has an ID. Get them from
GET /presentations/{id}
- Slide size — default is 10x5.63 inches (720x406.5 PT). Position elements accordingly
- Images — must be publicly accessible URLs. For private images, upload to Drive first
- Templates — use replaceAllText with
{{placeholder}} patterns for template-based decks
Error Handling
| Error | Meaning | Solution |
|---|
Drive not connected | No Drive OAuth token | Connect Google Drive first |
403 insufficient_scope | Token missing presentations scope | Reconnect Drive to get updated scopes |
404 not_found | Presentation doesn't exist | Check presentation ID |
400 invalid_request | Bad batch update request | Check request format against API docs |
Quick Reference
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
curl -s "https://api.atris.ai/api/integrations/google-slides/presentations" -H "Authorization: Bearer $TOKEN"
curl -s -X POST "https://api.atris.ai/api/integrations/google-slides/presentations" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"title":"My Deck"}'
curl -s "https://api.atris.ai/api/integrations/google-slides/presentations/PRES_ID" -H "Authorization: Bearer $TOKEN"
curl -s -X POST "https://api.atris.ai/api/integrations/google-slides/presentations/PRES_ID/batch-update" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"requests":[{"createSlide":{"slideLayoutReference":{"predefinedLayout":"TITLE_AND_BODY"}}}]}'
curl -s "https://api.atris.ai/api/integrations/google-slides/presentations/PRES_ID/export" -H "Authorization: Bearer $TOKEN"