Google Slides Agent
Drop this in
~/.claude/skills/slides/SKILL.mdand 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)")
# Check if Drive is connected (Slides piggybacks on Drive)
curl -s "https://api.atris.ai/api/integrations/google-drive/status" -H "Authorization: Bearer $TOKEN"
# If not connected, start Drive OAuth (includes Slides scope)
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": "Atris Labs - 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": "Atris Labs"
}
}
]
}
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 /presentationswith 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
# Get token
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
# List presentations
curl -s "https://api.atris.ai/api/integrations/google-slides/presentations" -H "Authorization: Bearer $TOKEN"
# Create 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":"My Deck"}'
# Get presentation (with all slides)
curl -s "https://api.atris.ai/api/integrations/google-slides/presentations/PRES_ID" -H "Authorization: Bearer $TOKEN"
# Add a slide with text
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"}}}]}'
# Export as PDF
curl -s "https://api.atris.ai/api/integrations/google-slides/presentations/PRES_ID/export" -H "Authorization: Bearer $TOKEN"