{"openapi":"3.1.0","info":{"title":"Rollstack API","version":"1","description":"Build, update and share Rollstack reports from your own code, scripts and AI clients. The API does what you do in the app: find and create reports, add data from your BI tools, spreadsheets or your own files, ask the slides agent to build and change slides, refresh reports from their sources, export them as PDF or PowerPoint, and share, schedule and email them. Owners and admins can also manage the organization, its members and its data source connections.\n\n## Getting started\n\n1. In Rollstack, open **Settings → Connected apps → API keys** and create a key with the scopes you need. Copy it: it starts with `rsk_` and is shown only once.\n2. Send it as a bearer token in the `Authorization` header of every request.\n3. Call `GET /me` to check the key: it answers the user and organization it belongs to and the scopes it carries.\n\n```bash\ncurl https://api.rollstack.com/public/v1/me \\\n  -H \"Authorization: Bearer rsk_...\"\n```\n\n## Authentication\n\nAn API key acts as the user who created it, in the one organization it was created in, and sees only what that user sees in the app. It never acts with more than the role its user had when they created it, and a key whose user is now a member loses the scopes only owners and admins may grant.\n\nKeys expire on the date set when they were created, if any. A user can revoke their keys in the app at any time, and deactivating a user revokes all of theirs. A missing, unknown, revoked or expired key answers 401.\n\n## Scopes\n\nMost endpoints need one scope, shown on their pages, and answer 403 with `api-key-missing-scope` when the key doesn't carry it; `GET /me` works with any valid key. Give a key only the scopes it needs. Some endpoints are also limited to owners and admins whatever the scope.\n\n| Scope | Allows | Owners and admins only |\n| --- | --- | --- |\n| `organization:read` | Read the organization's settings and its LLM provider |  |\n| `organization:write` | Change the organization's settings and its LLM provider | Yes |\n| `users:read` | List members and pending invites | Yes |\n| `users:write` | Change members' roles, deactivate and reactivate them, invite users and delete invites | Yes |\n| `connections:read` | List connections and their users, search their dashboards and the user's spreadsheets |  |\n| `connections:write` | Create, update and delete connections, and manage their users and admins |  |\n| `credentials:write` | Replace a connection's credentials |  |\n| `smtp:read` | List SMTP connections |  |\n| `smtp:write` | Add and delete SMTP connections |  |\n| `slide_decks:read` | List folders and reports, read their content, datasheets, schedules, email settings, messages and runs, and export them |  |\n| `slide_decks:write` | Create, update, delete, share and schedule reports, add their sources and upload files |  |\n| `slide_decks:run` | Message the slides agent, and start and cancel runs |  |\n| `slide_decks:email` | Set up and send report emails |  |\n\n## Requests and responses\n\n- Bodies are JSON, except the workbook an uploaded file can take as `multipart/form-data`. Fields an endpoint doesn't accept are rejected rather than ignored.\n- Dates are ISO 8601 strings in UTC. Ids are strings, except users', which are numbers.\n- `GET /reports` answers pages of up to `limit` reports: pass the `nextCursor` it answers as `cursor` for the next page, until it is null. Other lists answer every item at once.\n- Work that takes a while answers `202 Accepted` with an id right away: a message to the slides agent or a run. Follow it with its `GET`, which waits up to `waitSeconds` (20 by default, 30 at most) for the work to finish and answers as soon as it does, so call it again while the status is `queued` or `running`.\n\n## Errors\n\nEvery error answers a JSON body with a stable, machine-readable `code` and a `message` for people, such as `{ \"code\": \"api-key-missing-scope\", \"message\": \"This API key does not have the scope this endpoint requires\" }`.\n\n| Status | Means |\n| --- | --- |\n| 400 | The request is invalid. `data-validation-error` says which fields failed and why |\n| 401 | The key is missing, unknown, revoked (`api-key-invalid`) or expired (`api-key-expired`), or its user left the organization (`api-key-organization-left`). The `WWW-Authenticate` header says where to sign in with OAuth |\n| 403 | The key lacks the endpoint's scope (`api-key-missing-scope`, with the scope in the `WWW-Authenticate` header), or the user isn't an owner or admin (`require-admin-permission`) |\n| 404 | The resource or path doesn't exist |\n| 429 | Too many requests (`rate-limit-exceeded`): wait the seconds in the `Retry-After` header |\n| 5xx | Something failed on our side: retry later |\n\n## Rate limits\n\nEach API key may make 120 requests a minute. Calls that cost far more than a read have lower limits of their own, counted per user across all their keys and AI clients:\n\n| Calls | Limit |\n| --- | --- |\n| Messages to the slides agent | 6 a minute |\n| Exports and slide images | 10 a minute |\n| Datasheet data reads | 30 a minute |\n| Report viewer slide loads (MCP) | 60 a minute |\n| Email sends, test sends included | 5 a minute |\n| LLM provider saves | 10 a minute for the organization |\n\nResponses report how much of the key's per-minute limit is left, so a client can slow down before it gets a 429: `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` (seconds until the minute resets) and `RateLimit-Policy`. The lower limits above aren't in these headers. Past any limit, calls answer 429 with a `Retry-After` header: wait that long before calling again, whatever `RateLimit-Remaining` says. An MCP tool call past one of the lower limits returns an error result instead, with the `rate-limit-exceeded` code and a message that says how long to wait.\n\n## Versioning\n\nThe version is in the path: `/public/v1`. Changes within v1 only add: new endpoints, new optional request fields, new response fields and new values in fields such as a status or an error `code`, so ignore fields you don't know and handle values you don't know. An endpoint or field that gets replaced keeps working, and its page says it is deprecated and what replaces it. A change that would break existing calls comes as a new version under a new path, with v1 still running alongside it.\n\n### Deprecation and sunset\n\nA deprecated endpoint or field is marked `deprecated` in the OpenAPI document and on its page, and keeps working for as long as v1 does. When a new version replaces v1, v1 keeps running for at least 12 months after it ships. Through that time, v1 responses carry a `Deprecation` header with the date v1 was deprecated (RFC 9745) and a `Sunset` header with the date it stops answering (RFC 8594), and both dates are announced in the [product updates](https://docs.rollstack.com/changelog).\n\n## MCP server\n\nAI clients such as Claude can also use this API as an MCP server: POST JSON-RPC to `/public/v1/mcp` over Streamable HTTP with the same bearer API key, or sign in with OAuth from a client that supports it. Its tools, named by operationId, find, build, edit, run, export, share, schedule and email reports, upload files and message the slides agent. It lists only the tools the key can call. Everything else, such as deleting reports or managing members or connections, is REST-only.\n\n### Connect an AI assistant\n\nUse Rollstack when someone wants a slide deck or report built or kept up to date from their company's data, such as warehouses, BI dashboards and spreadsheets, in their own template, refreshed on a schedule or emailed.\n\nAdd the MCP server, `https://api.rollstack.com/public/v1/mcp`, to the assistant and sign in with Rollstack:\n\n- **Claude** (claude.ai and the desktop app): in Connectors, add a custom connector with this URL, then Connect. On Team and Enterprise plans an owner adds it in the organization's settings first.\n- **ChatGPT**: Settings → Plugins → MCPs → Add → Add MCP server, with Streamable HTTP and this URL. Save, then Authenticate. On Business and Enterprise plans an admin allows custom servers first.\n- **Claude Code**: `claude mcp add --transport http rollstack https://api.rollstack.com/public/v1/mcp`, then `/mcp` to sign in.\n- **Cursor**: add `{ \"mcpServers\": { \"rollstack\": { \"url\": \"https://api.rollstack.com/public/v1/mcp\" } } }` to `~/.cursor/mcp.json`, then sign in when it asks.\n- **Other clients**: send an API key as a bearer token.\n\nSigning in asks the user to approve the scopes the assistant asked for. The assistant can then do what they approved, within their role: a member can't grant the scopes only owners and admins have. Each sign-in creates a key that lasts 90 days, listed in [Settings → Connected apps](https://app.rollstack.com/settings/connected-apps) as a Connected app, where the user can revoke it.\n\nThings to ask it:\n\n- \"Build a quarterly business review deck from our Tableau dashboards\"\n- \"Refresh the data in my weekly sales report and email it to the team\"\n- \"Create one deck per region from this template\"\n- \"Schedule the board report to update every Monday\"\n\n| Tool | Scope | Owners and admins only |\n| --- | --- | --- |\n| `listReports` | `slide_decks:read` |  |\n| `getReport` | `slide_decks:read` |  |\n| `createReport` | `slide_decks:write` |  |\n| `updateReport` | `slide_decks:write` |  |\n| `getReportMessage` | `slide_decks:read` |  |\n| `sendReportMessage` | `slide_decks:run` |  |\n| `approveReportMessageProposal` | `slide_decks:run` |  |\n| `cancelReportMessage` | `slide_decks:run` |  |\n| `rejectReportMessageProposal` | `slide_decks:run` |  |\n| `getReportRun` | `slide_decks:read` |  |\n| `startReportRun` | `slide_decks:run` |  |\n| `cancelReportRun` | `slide_decks:run` |  |\n| `exportReport` | `slide_decks:read` |  |\n| `getReportContent` | `slide_decks:read` |  |\n| `getReportSlideImages` | `slide_decks:read` |  |\n| `showReport` | `slide_decks:read` |  |\n| `getReportViewerSlideImages` | `slide_decks:read` |  |\n| `createDataset` | `slide_decks:write` |  |\n| `replaceDataset` | `slide_decks:write` |  |\n| `deleteDataset` | `slide_decks:write` |  |\n| `listReportDatasheets` | `slide_decks:read` |  |\n| `getReportDatasheetData` | `slide_decks:read` |  |\n| `addReportDatasheets` | `slide_decks:write` |  |\n| `getReportParameters` | `slide_decks:read` |  |\n| `createReportParameter` | `slide_decks:write` |  |\n| `shareReport` | `slide_decks:write` |  |\n| `unshareReport` | `slide_decks:write` |  |\n| `updateReportSchedules` | `slide_decks:write` |  |\n| `getReportEmailConfig` | `slide_decks:read` |  |\n| `updateReportEmailConfig` | `slide_decks:email` |  |\n| `sendReportEmail` | `slide_decks:email` |  |\n| `sendReportTestEmail` | `slide_decks:email` |  |\n| `listBursts` | `slide_decks:read` |  |\n| `listBurstVariants` | `slide_decks:read` |  |\n| `addBurstVariants` | `slide_decks:write` |  |\n| `createBurst` | `slide_decks:write` |  |\n| `startBurstRun` | `slide_decks:run` |  |\n| `updateBurstVariantRecipients` | `slide_decks:email` |  |\n| `removeBurstVariants` | `slide_decks:write` |  |\n| `listConnections` | `connections:read` |  |\n| `searchDashboards` | `connections:read` |  |\n| `getDashboard` | `connections:read` |  |\n| `searchSpreadsheets` | `connections:read` |  |\n| `getSpreadsheet` | `connections:read` |  |\n| `listSmtpConnections` | `smtp:read` |  |\n| `listFolders` | `slide_decks:read` |  |\n| `submitFeedback` | Any valid key |  |\n| `listMembers` | `users:read` | Yes |"},"servers":[{"url":"https://api.rollstack.com/public/v1"}],"security":[{"apiKey":[]},{"oauth2":[]}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"A personal API key, starting with rsk_"},"oauth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://api.rollstack.com/authorize","tokenUrl":"https://api.rollstack.com/token","scopes":{"organization:read":"Read the organization's settings and its LLM provider","organization:write":"Change the organization's settings and its LLM provider","users:read":"List members and pending invites","users:write":"Change members' roles, deactivate and reactivate them, invite users and delete invites","connections:read":"List connections and their users, search their dashboards and the user's spreadsheets","connections:write":"Create, update and delete connections, and manage their users and admins","credentials:write":"Replace a connection's credentials","smtp:read":"List SMTP connections","smtp:write":"Add and delete SMTP connections","slide_decks:read":"List folders and reports, read their content, datasheets, schedules, email settings, messages and runs, and export them","slide_decks:write":"Create, update, delete, share and schedule reports, add their sources and upload files","slide_decks:run":"Message the slides agent, and start and cancel runs","slide_decks:email":"Set up and send report emails"}}}}},"schemas":{"Error":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"code":{"type":"string","description":"A stable, machine-readable code for the error, such as `api-key-missing-scope` or `data-validation-error`. Use it, rather than `message`, to handle specific errors in your code."},"message":{"type":"string","description":"A human-readable explanation of what went wrong, to log or show to people. When the request's path parameters, query or body are invalid (`data-validation-error`), it lists each invalid field by its path, with the problem, such as `body.emails.0: Invalid email address`."}},"required":["code","message"],"additionalProperties":false}}},"tags":[{"name":"Reports","description":"Find, create and manage reports. A report lives in a folder, has one owner, and is shared with other members who can view or edit it. Each report answers the permission the user has on it and a link that opens it in Rollstack.\n\nMost reports are slide decks built in Rollstack, whose `type` is `SlideDeck`. Older reports update a file in Google Drive or OneDrive, such as a Google Slides presentation, or send an email. Every report can be listed, read, renamed, moved, deleted, shared, scheduled and run. The other `/reports/{id}` endpoints take `SlideDeck` reports only, as their `id` says, and return `400` for other types.\n\nTo fill a new report, add its data in Datasheets, then ask the slides agent in Chat. To refresh an existing one, start a run."},{"name":"Chat","description":"Ask the slides agent to build or change a report, or to answer a question about it, as in the chat of the app.\n\n1. Send a message with `sendReportMessage`. It answers at once with the message id.\n2. Call `getReportMessage` until its status is `completed` or `failed`. Each call waits up to `waitSeconds` for the agent to finish.\n3. Check the slides it changed with `getReportSlideImages` or `getReportContent`, passing the replies' `changedSlideIds`.\n4. A reply can propose a change to the report's schedules, email or parameters, or to send it by email, instead of making it. Show the user its `proposal`, then decide it as they say with `approveReportMessageProposal` or `rejectReportMessageProposal`.\n\nContinue the conversation by sending the next message with the same `chatId`. Every chat also shows in the app, with a link in `appUrl`."},{"name":"Runs","description":"Update a report from its sources. A run reads every datasheet again, or only the ones you pass, recalculates the report's numbers, and repairs with AI the calculations and slides the new data broke. Schedules start the same run.\n\nOn a report whose `type` isn't `SlideDeck`, a run refreshes every visualization instead, as Update in the app does. It updates the report's file, such as a Google Slides presentation; an `Email` report has no file. Recipients get the report by email when its email trigger is `all`. Its `errors` then name the visualizations it could not refresh.\n\nStart a run, then follow it with `getReportRun` until it ends. A report runs once at a time: starting a run while one is going answers that run instead."},{"name":"Exports","description":"Download a report as a PDF or a PowerPoint file, as viewers see it. The export answers a link to the file, valid for 15 minutes, so download it right away.\n\nExports render the whole report, so they have a lower rate limit than other calls."},{"name":"Content","description":"What viewers see on a report, for reading or checking it without downloading a file. `getReportContent` answers the text of each visible slide and the values in its charts and tables. `getReportSlideImages` renders slides as images, to check their layout.\n\nBoth take slide ids, so after a message to the slides agent you can look at only the slides it changed."},{"name":"Uploaded files","description":"Your own data, for the slides agent to build slides from: a CSV file sent as JSON, or an Excel workbook sent as a file, as with Upload files in the app. Uploaded files suit data that lives outside a connected BI tool or spreadsheet, such as an export from another system.\n\nUpload a CSV file with `createDataset`, add it to a report with `addReportDatasheets`, then pass the datasheet id to the slides agent. Replace its content later and the reports built on it show the new data after their next run."},{"name":"Datasheets","description":"The data behind a report's charts and tables. A datasheet reads one source, an uploaded file, a dashboard tab of a connection or a range of a spreadsheet, and keeps a copy of what it read; the report's charts and tables are drawn from those copies.\n\nAdd sources with `addReportDatasheets`, see when each was last read and whether it failed with `listReportDatasheets`, and read the table behind a chart with `getReportDatasheetData`."},{"name":"Parameters","description":"Named values of a report, such as a region, that it writes into the filters of the dashboards its datasheets read. One parameter can link differently named filters on several dashboards, and setting its value filters all of them the same way. A burst's variants each hold their own value of the parameters it varies by.\n\nSee a report's parameters and the filters they can link with `getReportParameters`, then create one with `createReportParameter`. Only reports that read a dashboard have filters to link: one built only from uploaded files and spreadsheet ranges can't have parameters."},{"name":"Sharing","description":"Who a report is shared with. Share a report with a member of the organization to let them `view` or `edit` it; they get an email. Sharing again with another permission changes it.\n\nThe owner always has access. `getReport` lists everyone the report is shared with."},{"name":"Schedules","description":"When a report updates on its own. Each schedule starts a run of the whole report at the times it sets, in its timezone: hourly at chosen times of day, or on a cron expression for daily, weekly, monthly, quarterly and yearly ones.\n\nA report has up to 10 schedules, replaced together. Schedules are checked every 15 minutes, so a cron expression must run at minute 0, 15, 30 or 45."},{"name":"Email","description":"Who a report's email goes to and how it is sent: its recipients, the sender it goes out through, whether it carries the report as a link, a PDF or a PowerPoint file, and which successful runs send it on their own. Set it up once, then send it now or let the report's runs send it.\n\nSend a test email to yourself to check how it looks first. Every send emails all the recipients, so sends have a low rate limit."},{"name":"Bursts","description":"A burst makes one report per audience from a template report: each variant is a copy of the template that holds its own values of the report parameters the burst varies by, such as a region or an account, so its datasheets read only its data.\n\nMake a report the template of a burst with `createBurst`, or find one with `listBursts`, then see its variants, where their runs stand and who they are emailed to with `listBurstVariants`. Add variants by their parameter values, remove them, run them all with `startBurstRun`, and set who each one is emailed to. Each variant is also a report, so the `/reports/{id}` endpoints work on it."},{"name":"Connections","description":"Data source connections: the Looker, Metabase, Omni, Lightdash, Sigma, Tableau, Power BI and Salesforce instances, and Snowflake and Databricks warehouses, reports read data from. Credentials are write-only and tested before they are saved; reads never answer them.\n\nUse `searchDashboards` and `getDashboard` to find a dashboard and its tabs, then add it to a report with `addReportDatasheets`. Snowflake and Databricks connect through browser OAuth, so only the app can create them or change their credentials."},{"name":"Connection users","description":"Who can use a connection. Each user reads data with their own access to the connection; a user without one uses the default user's, when the connection has one.\n\nWith `autoProvision` on, new members of the organization get access on their own. Removing a user also deletes the syncs that read through their access."},{"name":"Connection admins","description":"Who can manage a connection. A connection has one owner and any number of admins. Admins manage the connection's users; only the owner can add or remove admins, or delete the connection.\n\nOwnership moves only in the app."},{"name":"Spreadsheets","description":"The Google Sheets and Excel files the user added in Rollstack, read with the user's own Google or Microsoft account. Rollstack sees only the files added in the app, not the user's whole Drive or OneDrive.\n\nFind a file with `searchSpreadsheets`, list its sheets with `getSpreadsheet`, then add a range of a sheet to a report with `addReportDatasheets`."},{"name":"SMTP connections","description":"The SMTP connections report emails go out through: an SMTP login or a Google or Microsoft account. A connection is the user's own, or shared with the whole organization by an owner or admin.\n\nPick one in Email settings for a report. Credentials are write-only and checked with a test email before the connection is saved."},{"name":"Folders","description":"The folders that organize reports, as nested in the app. Each folder answers the permission the user has on it: `view`, `edit` or `manage`.\n\nPass a folder id as `folderId` to list the reports in it, or to create or move a report into it."},{"name":"Organization","description":"The API key's organization and its settings: its name and default timezone, the email domains members may be invited from, how reports update and link to their sources, and which features are on, such as insights, memories, spreadsheets and email analytics.\n\nAnyone with `organization:read` can read the settings. Changing them needs `organization:write`, which only owners and admins can grant a key."},{"name":"Members","description":"Members of the organization, their roles and access. A member's role is `owner`, `admin` or `member`; their authentication role, `viewer` or `editor`, lets them see or change the organization's SSO settings.\n\nCall `GET /me` first to check a key works: it answers the user the key acts as, the organization it belongs to, the role it acts with and the scopes it carries, with any valid key, whatever its scopes.\n\nOnly owners and admins may call the other endpoints, with a key carrying `users:read` or `users:write`. A key can make a member an admin or a member, never an owner. Deactivating a member removes them from the organization, revokes their API keys and deletes their invites; reactivating them brings them back, but not their keys."},{"name":"Invites","description":"Pending invites to join the organization, each with the role and authentication role the user joins with.\n\nOnly emails in the organization's allowed domains can be invited, so set its allowed domains first. Emails outside them, of existing members or already invited come back as rejected, with the reason, while the others are invited."},{"name":"LLM provider","description":"The organization's own LLM provider for the slides agent: its Anthropic, OpenAI, Azure AI Foundry, Amazon Bedrock or Google Vertex AI account, used instead of Rollstack's. Credentials are write-only: reads answer the provider's settings and status, never its keys.\n\nSetting one up is part of the Enterprise plan. Saving tests every model on the new keys first, so a provider that cannot answer is never saved."}],"x-tagGroups":[{"name":"Reports","tags":["Reports","Chat","Runs","Exports","Content","Uploaded files","Datasheets","Parameters","Sharing","Schedules","Email","Bursts"]},{"name":"Connections","tags":["Connections","Connection users","Connection admins","Spreadsheets","SMTP connections"]},{"name":"Workspace","tags":["Folders"]},{"name":"Admin","tags":["Organization","Members","Invites","LLM provider"]}],"paths":{"/reports":{"get":{"operationId":"listReports","summary":"List reports","description":"The reports the user can see, of every type, newest first. Each report's type tells which endpoints work on it: the slides agent, exports, content, datasheets, parameters, email and ownership transfer take SlideDeck reports only. You can filter by folderId, name and type; when several are set, all must match, and name matching ignores case. Answers up to limit reports, 50 by default and 200 at most, and a nextCursor: pass it as cursor for the next page, until it is null.\n\nRequires the `slide_decks:read` scope.","tags":["Reports"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"folderId","in":"query","required":false,"description":"Only return reports directly in this folder, by its `id` from `listFolders`. Reports in its subfolders aren't included.","schema":{"description":"Only return reports directly in this folder, by its `id` from `listFolders`. Reports in its subfolders aren't included.","examples":["a3d5e7f9-1b2c-4d6e-8f0a-1b2c3d4e5f6a"],"type":"string"}},{"name":"name","in":"query","required":false,"description":"Only return reports whose name contains this text, ignoring case: `review` matches `Q3 Business Review`.","schema":{"description":"Only return reports whose name contains this text, ignoring case: `review` matches `Q3 Business Review`.","examples":["business review"],"type":"string","minLength":1}},{"name":"type","in":"query","required":false,"description":"Only return reports of this `type`, such as `SlideDeck` for the reports that the slides agent, exports and datasheets work on.","schema":{"description":"Only return reports of this `type`, such as `SlideDeck` for the reports that the slides agent, exports and datasheets work on.","examples":["SlideDeck"],"type":"string","enum":["GoogleDocs","GoogleSlides","MicrosoftPowerPoint","MicrosoftWord","Email","UploadedPPTXFile","SlideDeck"]}},{"name":"limit","in":"query","required":false,"description":"Maximum number of reports to return on this page, from 1 to 200. Defaults to `50`.","schema":{"default":50,"description":"Maximum number of reports to return on this page, from 1 to 200. Defaults to `50`.","type":"integer","minimum":1,"maximum":200}},{"name":"cursor","in":"query","required":false,"description":"Where to continue the list: pass the `nextCursor` returned with the previous page to get the next one. Omit it for the first page.","schema":{"description":"Where to continue the list: pass the `nextCursor` returned with the previous page to get the next one. Omit it for the first page.","examples":["6c1f9a2e-3b4d-4e8f-9a1b-2c3d4e5f6a7b"],"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the report. Pass it as `id` to the other `/reports/{id}` endpoints."},"type":{"type":"string","enum":["GoogleDocs","GoogleSlides","MicrosoftPowerPoint","MicrosoftWord","Email","UploadedPPTXFile","SlideDeck"],"description":"The kind of report, which decides the endpoints that work on it.\n\n- `SlideDeck`: a slide deck built in Rollstack. Every `/reports/{id}` endpoint works on it.\n- `GoogleSlides`, `GoogleDocs`, `MicrosoftPowerPoint`, `MicrosoftWord`: a file in Google Drive or OneDrive that Rollstack updates with its visualizations.\n- `UploadedPPTXFile`: a PowerPoint file uploaded to Rollstack, which it updates the same way.\n- `Email`: an email report, whose visualizations Rollstack sends in an email.\n\nOn a report that isn't a `SlideDeck`, only `getReport`, `updateReport`, `deleteReport`, `shareReport`, `unshareReport`, `getReportSchedules`, `updateReportSchedules`, `startReportRun`, `getReportRun` and `cancelReportRun` work. The other `/reports/{id}` endpoints take `SlideDeck` reports only, as their `id` says, and return `400`."},"name":{"type":"string","description":"Name of the report, as members see it in Rollstack. Change it with `updateReport`."},"folderId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The folder the report is in, by its `id` in `listFolders`. `null` when the report is at the top level, outside any folder."},"owner":{"type":"object","properties":{"id":{"type":"number","description":"The owner's user id, the same as their `id` in `listMembers`."},"name":{"type":"string","description":"The owner's name, as shown in Rollstack."},"email":{"type":"string","description":"The owner's email address. Rollstack emails this address when a scheduled run of the report fails, while `notifyOnFailure` is `true`."}},"required":["id","name","email"],"additionalProperties":false,"description":"The member who owns the report: whoever created it, unless ownership has since been transferred, in the app or with `transferReportOwnership`. Only the owner can delete the report."},"permission":{"anyOf":[{"type":"string","enum":["view","comment","edit"]},{"type":"null"}],"description":"Your access to the report, as the user the API key belongs to. `view` lets you open and export it, and see its datasheets, runs, schedules and email setup. `comment` also lets you add, reply to and resolve comments on its slides. `edit` also lets you change it: rename or move it, chat with the slides agent about it, add datasheets and read their data, start runs, set its schedules and email, send its email, and share it. It's never `null` here, since the API only returns reports you can at least view."},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The report's timezone, such as `America/New_York`. The slides agent uses it to tell today's date, and the report's emails show the time of its last successful update (`{{last_updated_at}}`) in it. On a report that updates a file, such as a Google Slides presentation, it's also the timezone of the file's date variables, unless the organization's `timezone` replaces it. Schedules don't use it: each has its own `timezone`. `null` when the report has none, in which case the slides agent uses UTC. Reports created with `createReport` start with the organization's `timezone` from `getOrganization`, if it has one."},"notifyOnFailure":{"type":"boolean","description":"Whether Rollstack emails the report's owner when a scheduled run fails or some of its datasheets, or a file's visualizations, fail to refresh, copying everyone in `notificationMailingList`. Runs started in the app or with `startReportRun` never send this email. New reports start with `true`."},"lastSyncedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the report's latest run ended, whatever its outcome. `null` if the report has never run."},"lastSuccessfulUpdateAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the report's latest fully successful run ended: one that refreshed every datasheet it ran on, or every visualization on a report that updates a file, with none failing. Runs with nothing to refresh don't count. The report's emails show this time as `{{last_updated_at}}`. `null` until the report has had such a run."},"lastRunStatus":{"anyOf":[{"type":"string","enum":["running","completed","failed","cancelled","timed_out"]},{"type":"null"}],"description":"How the report's latest run ended. `completed`: it finished, even if some datasheets or visualizations failed to refresh or it had none to refresh; on a `SlideDeck` report, `listReportDatasheets` shows each datasheet's `error`. `failed`: it stopped on an error, or none of its datasheets or visualizations could be refreshed. `cancelled`: it was stopped before it finished, for example with `cancelReportRun`. `null` if the report has never run. `running` and `timed_out` never appear here: check `running` to see whether a run is in progress."},"running":{"type":"boolean","description":"Whether a run of the report is in progress, whoever started it, such as you with `startReportRun`, a member in the app, or one of its schedules. While it's `true`, `startReportRun` returns that run instead of starting another."},"appUrl":{"type":"string","format":"uri","description":"Link that opens the report in Rollstack."},"createdAt":{"description":"When the report was created. `listReports` returns the newest first.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the report's details last changed, such as its name, folder or owner, or the outcome of its latest run.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","type","name","folderId","owner","permission","timezone","notifyOnFailure","lastSyncedAt","lastSuccessfulUpdateAt","lastRunStatus","running","appUrl","createdAt","updatedAt"],"additionalProperties":false},"description":"The reports on this page, of every `type`, most recently created first."},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass it as `cursor` to get the next page of reports. `null` when there are no more."}},"required":["data","nextCursor"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createReport","summary":"Create report","description":"Creates a report of type SlideDeck, in a folder the user can see when folderId is set. It starts empty, or with the look of templateDeckId: its theme, masters and layouts, without its slides. The template must be a SlideDeck report the user may duplicate.\n\nRequires the `slide_decks:write` scope.","tags":["Reports"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Name for the report, as members will see it in Rollstack. Leading and trailing spaces are removed, and it can't be blank.","examples":["Q3 business review"]},"folderId":{"description":"The folder to create the report in, by its `id` from `listFolders`; it must be one you can see. Members with access to the folder can then open the report too, with the access the folder gives them. If omitted, the report is created at the top level, outside any folder.","examples":["a3d5e7f9-1b2c-4d6e-8f0a-1b2c3d4e5f6a"],"type":"string"},"templateDeckId":{"description":"An existing report whose design the new report starts with, by its `id` from `listReports`: its theme, slide masters, layouts and slide size, but none of its slides or data. Its `type` must be `SlideDeck`, and you need at least view access to it. If omitted, the report starts with no slides and Rollstack's default theme and layouts.","examples":["6c1f9a2e-3b4d-4e8f-9a1b-2c3d4e5f6a7b"],"type":"string"}},"required":["name"],"additionalProperties":false}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the report. Pass it as `id` to the other `/reports/{id}` endpoints."},"type":{"type":"string","enum":["GoogleDocs","GoogleSlides","MicrosoftPowerPoint","MicrosoftWord","Email","UploadedPPTXFile","SlideDeck"],"description":"The kind of report, which decides the endpoints that work on it.\n\n- `SlideDeck`: a slide deck built in Rollstack. Every `/reports/{id}` endpoint works on it.\n- `GoogleSlides`, `GoogleDocs`, `MicrosoftPowerPoint`, `MicrosoftWord`: a file in Google Drive or OneDrive that Rollstack updates with its visualizations.\n- `UploadedPPTXFile`: a PowerPoint file uploaded to Rollstack, which it updates the same way.\n- `Email`: an email report, whose visualizations Rollstack sends in an email.\n\nOn a report that isn't a `SlideDeck`, only `getReport`, `updateReport`, `deleteReport`, `shareReport`, `unshareReport`, `getReportSchedules`, `updateReportSchedules`, `startReportRun`, `getReportRun` and `cancelReportRun` work. The other `/reports/{id}` endpoints take `SlideDeck` reports only, as their `id` says, and return `400`."},"name":{"type":"string","description":"Name of the report, as members see it in Rollstack. Change it with `updateReport`."},"folderId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The folder the report is in, by its `id` in `listFolders`. `null` when the report is at the top level, outside any folder."},"owner":{"type":"object","properties":{"id":{"type":"number","description":"The owner's user id, the same as their `id` in `listMembers`."},"name":{"type":"string","description":"The owner's name, as shown in Rollstack."},"email":{"type":"string","description":"The owner's email address. Rollstack emails this address when a scheduled run of the report fails, while `notifyOnFailure` is `true`."}},"required":["id","name","email"],"additionalProperties":false,"description":"The member who owns the report: whoever created it, unless ownership has since been transferred, in the app or with `transferReportOwnership`. Only the owner can delete the report."},"permission":{"anyOf":[{"type":"string","enum":["view","comment","edit"]},{"type":"null"}],"description":"Your access to the report, as the user the API key belongs to. `view` lets you open and export it, and see its datasheets, runs, schedules and email setup. `comment` also lets you add, reply to and resolve comments on its slides. `edit` also lets you change it: rename or move it, chat with the slides agent about it, add datasheets and read their data, start runs, set its schedules and email, send its email, and share it. It's never `null` here, since the API only returns reports you can at least view."},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The report's timezone, such as `America/New_York`. The slides agent uses it to tell today's date, and the report's emails show the time of its last successful update (`{{last_updated_at}}`) in it. On a report that updates a file, such as a Google Slides presentation, it's also the timezone of the file's date variables, unless the organization's `timezone` replaces it. Schedules don't use it: each has its own `timezone`. `null` when the report has none, in which case the slides agent uses UTC. Reports created with `createReport` start with the organization's `timezone` from `getOrganization`, if it has one."},"notifyOnFailure":{"type":"boolean","description":"Whether Rollstack emails the report's owner when a scheduled run fails or some of its datasheets, or a file's visualizations, fail to refresh, copying everyone in `notificationMailingList`. Runs started in the app or with `startReportRun` never send this email. New reports start with `true`."},"lastSyncedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the report's latest run ended, whatever its outcome. `null` if the report has never run."},"lastSuccessfulUpdateAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the report's latest fully successful run ended: one that refreshed every datasheet it ran on, or every visualization on a report that updates a file, with none failing. Runs with nothing to refresh don't count. The report's emails show this time as `{{last_updated_at}}`. `null` until the report has had such a run."},"lastRunStatus":{"anyOf":[{"type":"string","enum":["running","completed","failed","cancelled","timed_out"]},{"type":"null"}],"description":"How the report's latest run ended. `completed`: it finished, even if some datasheets or visualizations failed to refresh or it had none to refresh; on a `SlideDeck` report, `listReportDatasheets` shows each datasheet's `error`. `failed`: it stopped on an error, or none of its datasheets or visualizations could be refreshed. `cancelled`: it was stopped before it finished, for example with `cancelReportRun`. `null` if the report has never run. `running` and `timed_out` never appear here: check `running` to see whether a run is in progress."},"running":{"type":"boolean","description":"Whether a run of the report is in progress, whoever started it, such as you with `startReportRun`, a member in the app, or one of its schedules. While it's `true`, `startReportRun` returns that run instead of starting another."},"appUrl":{"type":"string","format":"uri","description":"Link that opens the report in Rollstack."},"createdAt":{"description":"When the report was created. `listReports` returns the newest first.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the report's details last changed, such as its name, folder or owner, or the outcome of its latest run.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"notificationMailingList":{"type":"array","items":{"type":"string"},"description":"Email addresses Rollstack copies when it emails the owner about a failed scheduled run, while `notifyOnFailure` is `true`. Change the list with `updateReport`."},"schedules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the schedule. `updateReportSchedules` replaces every schedule, so the ids change each time you call it."},"frequency":{"type":"string","enum":["daily","weekly","monthly","quarterly","hourly","yearly"],"description":"How often the schedule runs. `hourly` runs every day at each time in `selectedTimes`. `daily`, `weekly`, `monthly` and `quarterly` run whenever `cronExpression` fires; those made in the app run every day, on chosen weekdays, on chosen days of the month, or every three months, respectively. `yearly` can't be set through the API or the app, and also runs on `cronExpression`."},"cronExpression":{"type":"string","description":"When the schedule runs, as a five-field cron expression (minute, hour, day of month, month, day of week) in the schedule's `timezone`. For an `hourly` schedule, Rollstack generates it from `selectedTimes` and runs the report at those times instead. Monthly schedules made in the app can use `L` and `#`, such as `0 9 L * *` (last day of the month) or `0 9 ? * 1#1` (first Monday)."},"selectedTimes":{"type":"array","items":{"type":"string"},"description":"The times of day an `hourly` schedule runs, every day, as 24-hour `HH:mm` in the schedule's `timezone`. Other frequencies don't use it; it's empty on those set through the API."},"startDate":{"description":"When the schedule starts: it never runs the report before this date and time. This is a local date and time in the schedule's `timezone`, written as if it were UTC: `2026-11-02T09:00:00Z` means 9:00 on November 2, 2026 in that timezone, not 9:00 UTC.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"endDate":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the schedule ends: it never runs the report after this date and time. `null` if the schedule never ends. Like `startDate`, this is a local date and time in the schedule's `timezone`, written as if it were UTC."},"timezone":{"type":"string","description":"The timezone the schedule runs in. Its run times (`cronExpression` or `selectedTimes`), `startDate` and `endDate` are all local times in this timezone, so a schedule set for 9:00 keeps running at 9:00 local time when daylight saving time starts or ends. Given as an IANA timezone name, such as `America/New_York`."},"nextRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the schedule will next run the report. `null` if it has no runs left before its `endDate`. Unlike `startDate` and `endDate`, this is an actual UTC time."}},"required":["id","frequency","cronExpression","selectedTimes","startDate","endDate","timezone","nextRunAt"],"additionalProperties":false},"description":"The report's schedules: when Rollstack runs the report on its own to update it with fresh data. Empty if it has none, in which case the report only runs when someone starts a run. Replace them with `updateReportSchedules`."},"sharedWith":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"number","description":"The member's user id. Pass it as `userId` to `shareReport` to change their access, or to `unshareReport` to remove it."},"email":{"type":"string","description":"The member's email address, as shown in Rollstack."},"name":{"type":"string","description":"The member's name, as shown in Rollstack."},"permission":{"type":"string","enum":["view","comment","edit"],"description":"What the member can do with the report. `view` lets them open, export and duplicate it. `comment` also lets them add, reply to and resolve comments on its slides. `edit` also lets them change its slides, data, schedules, email and other settings, run it, send its email, chat with the slides agent about it, and manage who it's shared with. Neither lets them delete the report or transfer its ownership."}},"required":["userId","email","name","permission"],"additionalProperties":false},"description":"Members the report is shared with directly, with their access. Members who can open it through its folder aren't listed. Change this list with `shareReport` and `unshareReport`."}},"required":["id","type","name","folderId","owner","permission","timezone","notifyOnFailure","lastSyncedAt","lastSuccessfulUpdateAt","lastRunStatus","running","appUrl","createdAt","updatedAt","notificationMailingList","schedules","sharedWith"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}":{"get":{"operationId":"getReport","summary":"Get report","description":"A report of any type with its schedules, who it is shared with and who is emailed when a run fails. lastRunStatus and running tell how its latest run went and whether one is going, and appUrl opens it in Rollstack. type tells which other endpoints work on it.\n\nRequires the `slide_decks:read` scope.","tags":["Reports"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`.","schema":{"type":"string","description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`."}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the report. Pass it as `id` to the other `/reports/{id}` endpoints."},"type":{"type":"string","enum":["GoogleDocs","GoogleSlides","MicrosoftPowerPoint","MicrosoftWord","Email","UploadedPPTXFile","SlideDeck"],"description":"The kind of report, which decides the endpoints that work on it.\n\n- `SlideDeck`: a slide deck built in Rollstack. Every `/reports/{id}` endpoint works on it.\n- `GoogleSlides`, `GoogleDocs`, `MicrosoftPowerPoint`, `MicrosoftWord`: a file in Google Drive or OneDrive that Rollstack updates with its visualizations.\n- `UploadedPPTXFile`: a PowerPoint file uploaded to Rollstack, which it updates the same way.\n- `Email`: an email report, whose visualizations Rollstack sends in an email.\n\nOn a report that isn't a `SlideDeck`, only `getReport`, `updateReport`, `deleteReport`, `shareReport`, `unshareReport`, `getReportSchedules`, `updateReportSchedules`, `startReportRun`, `getReportRun` and `cancelReportRun` work. The other `/reports/{id}` endpoints take `SlideDeck` reports only, as their `id` says, and return `400`."},"name":{"type":"string","description":"Name of the report, as members see it in Rollstack. Change it with `updateReport`."},"folderId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The folder the report is in, by its `id` in `listFolders`. `null` when the report is at the top level, outside any folder."},"owner":{"type":"object","properties":{"id":{"type":"number","description":"The owner's user id, the same as their `id` in `listMembers`."},"name":{"type":"string","description":"The owner's name, as shown in Rollstack."},"email":{"type":"string","description":"The owner's email address. Rollstack emails this address when a scheduled run of the report fails, while `notifyOnFailure` is `true`."}},"required":["id","name","email"],"additionalProperties":false,"description":"The member who owns the report: whoever created it, unless ownership has since been transferred, in the app or with `transferReportOwnership`. Only the owner can delete the report."},"permission":{"anyOf":[{"type":"string","enum":["view","comment","edit"]},{"type":"null"}],"description":"Your access to the report, as the user the API key belongs to. `view` lets you open and export it, and see its datasheets, runs, schedules and email setup. `comment` also lets you add, reply to and resolve comments on its slides. `edit` also lets you change it: rename or move it, chat with the slides agent about it, add datasheets and read their data, start runs, set its schedules and email, send its email, and share it. It's never `null` here, since the API only returns reports you can at least view."},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The report's timezone, such as `America/New_York`. The slides agent uses it to tell today's date, and the report's emails show the time of its last successful update (`{{last_updated_at}}`) in it. On a report that updates a file, such as a Google Slides presentation, it's also the timezone of the file's date variables, unless the organization's `timezone` replaces it. Schedules don't use it: each has its own `timezone`. `null` when the report has none, in which case the slides agent uses UTC. Reports created with `createReport` start with the organization's `timezone` from `getOrganization`, if it has one."},"notifyOnFailure":{"type":"boolean","description":"Whether Rollstack emails the report's owner when a scheduled run fails or some of its datasheets, or a file's visualizations, fail to refresh, copying everyone in `notificationMailingList`. Runs started in the app or with `startReportRun` never send this email. New reports start with `true`."},"lastSyncedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the report's latest run ended, whatever its outcome. `null` if the report has never run."},"lastSuccessfulUpdateAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the report's latest fully successful run ended: one that refreshed every datasheet it ran on, or every visualization on a report that updates a file, with none failing. Runs with nothing to refresh don't count. The report's emails show this time as `{{last_updated_at}}`. `null` until the report has had such a run."},"lastRunStatus":{"anyOf":[{"type":"string","enum":["running","completed","failed","cancelled","timed_out"]},{"type":"null"}],"description":"How the report's latest run ended. `completed`: it finished, even if some datasheets or visualizations failed to refresh or it had none to refresh; on a `SlideDeck` report, `listReportDatasheets` shows each datasheet's `error`. `failed`: it stopped on an error, or none of its datasheets or visualizations could be refreshed. `cancelled`: it was stopped before it finished, for example with `cancelReportRun`. `null` if the report has never run. `running` and `timed_out` never appear here: check `running` to see whether a run is in progress."},"running":{"type":"boolean","description":"Whether a run of the report is in progress, whoever started it, such as you with `startReportRun`, a member in the app, or one of its schedules. While it's `true`, `startReportRun` returns that run instead of starting another."},"appUrl":{"type":"string","format":"uri","description":"Link that opens the report in Rollstack."},"createdAt":{"description":"When the report was created. `listReports` returns the newest first.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the report's details last changed, such as its name, folder or owner, or the outcome of its latest run.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"notificationMailingList":{"type":"array","items":{"type":"string"},"description":"Email addresses Rollstack copies when it emails the owner about a failed scheduled run, while `notifyOnFailure` is `true`. Change the list with `updateReport`."},"schedules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the schedule. `updateReportSchedules` replaces every schedule, so the ids change each time you call it."},"frequency":{"type":"string","enum":["daily","weekly","monthly","quarterly","hourly","yearly"],"description":"How often the schedule runs. `hourly` runs every day at each time in `selectedTimes`. `daily`, `weekly`, `monthly` and `quarterly` run whenever `cronExpression` fires; those made in the app run every day, on chosen weekdays, on chosen days of the month, or every three months, respectively. `yearly` can't be set through the API or the app, and also runs on `cronExpression`."},"cronExpression":{"type":"string","description":"When the schedule runs, as a five-field cron expression (minute, hour, day of month, month, day of week) in the schedule's `timezone`. For an `hourly` schedule, Rollstack generates it from `selectedTimes` and runs the report at those times instead. Monthly schedules made in the app can use `L` and `#`, such as `0 9 L * *` (last day of the month) or `0 9 ? * 1#1` (first Monday)."},"selectedTimes":{"type":"array","items":{"type":"string"},"description":"The times of day an `hourly` schedule runs, every day, as 24-hour `HH:mm` in the schedule's `timezone`. Other frequencies don't use it; it's empty on those set through the API."},"startDate":{"description":"When the schedule starts: it never runs the report before this date and time. This is a local date and time in the schedule's `timezone`, written as if it were UTC: `2026-11-02T09:00:00Z` means 9:00 on November 2, 2026 in that timezone, not 9:00 UTC.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"endDate":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the schedule ends: it never runs the report after this date and time. `null` if the schedule never ends. Like `startDate`, this is a local date and time in the schedule's `timezone`, written as if it were UTC."},"timezone":{"type":"string","description":"The timezone the schedule runs in. Its run times (`cronExpression` or `selectedTimes`), `startDate` and `endDate` are all local times in this timezone, so a schedule set for 9:00 keeps running at 9:00 local time when daylight saving time starts or ends. Given as an IANA timezone name, such as `America/New_York`."},"nextRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the schedule will next run the report. `null` if it has no runs left before its `endDate`. Unlike `startDate` and `endDate`, this is an actual UTC time."}},"required":["id","frequency","cronExpression","selectedTimes","startDate","endDate","timezone","nextRunAt"],"additionalProperties":false},"description":"The report's schedules: when Rollstack runs the report on its own to update it with fresh data. Empty if it has none, in which case the report only runs when someone starts a run. Replace them with `updateReportSchedules`."},"sharedWith":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"number","description":"The member's user id. Pass it as `userId` to `shareReport` to change their access, or to `unshareReport` to remove it."},"email":{"type":"string","description":"The member's email address, as shown in Rollstack."},"name":{"type":"string","description":"The member's name, as shown in Rollstack."},"permission":{"type":"string","enum":["view","comment","edit"],"description":"What the member can do with the report. `view` lets them open, export and duplicate it. `comment` also lets them add, reply to and resolve comments on its slides. `edit` also lets them change its slides, data, schedules, email and other settings, run it, send its email, chat with the slides agent about it, and manage who it's shared with. Neither lets them delete the report or transfer its ownership."}},"required":["userId","email","name","permission"],"additionalProperties":false},"description":"Members the report is shared with directly, with their access. Members who can open it through its folder aren't listed. Change this list with `shareReport` and `unshareReport`."}},"required":["id","type","name","folderId","owner","permission","timezone","notifyOnFailure","lastSyncedAt","lastSuccessfulUpdateAt","lastRunStatus","running","appUrl","createdAt","updatedAt","notificationMailingList","schedules","sharedWith"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateReport","summary":"Update report","description":"Renames a report of any type, moves it, or changes its timezone or failure notifications. Renaming a report that updates a file, such as a Google Slides presentation, also renames the file, as the app does. Only its editors may.\n\nRequires the `slide_decks:write` scope.","tags":["Reports"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`.","schema":{"type":"string","description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"description":"New name for the report, as members will see it in Rollstack. Leading and trailing spaces are removed, and it can't be blank.","examples":["Q3 business review"],"type":"string","minLength":1},"folderId":{"description":"The folder to move the report to, by its `id` from `listFolders`; it must be one you can see. Pass `null` to move it to the top level, outside any folder. Members then get access to the report through the new folder, and the folders it's in, instead of the old one.","examples":["a3d5e7f9-1b2c-4d6e-8f0a-1b2c3d4e5f6a"],"anyOf":[{"type":"string"},{"type":"null"}]},"timezone":{"description":"The report's new timezone. The slides agent uses it to tell today's date, and the report's emails show the time of its last successful update (`{{last_updated_at}}`) in it. On a report that updates a file, it's also the timezone of the file's date variables, unless the organization's `timezone` replaces it. It doesn't change the report's schedules, which each have their own `timezone`: change those with `updateReportSchedules`. An IANA timezone name, such as `America/New_York`.","examples":["America/New_York"],"type":"string"},"notifyOnFailure":{"description":"Whether Rollstack should email the report's owner when a scheduled run fails or some of its datasheets fail to refresh, copying everyone in `notificationMailingList`. Set it to `false` to stop these emails. Runs started in the app or with `startReportRun` never send them.","type":"boolean"},"notificationMailingList":{"description":"Email addresses to copy when Rollstack emails the owner about a failed scheduled run, while `notifyOnFailure` is `true`. The list you send replaces the current one; send `[]` to clear it. Each address must belong to an active member of the organization, ignoring case. Up to 100 addresses, with no duplicates.","maxItems":100,"type":"array","items":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","examples":["jane@acme.com"]}}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the report. Pass it as `id` to the other `/reports/{id}` endpoints."},"type":{"type":"string","enum":["GoogleDocs","GoogleSlides","MicrosoftPowerPoint","MicrosoftWord","Email","UploadedPPTXFile","SlideDeck"],"description":"The kind of report, which decides the endpoints that work on it.\n\n- `SlideDeck`: a slide deck built in Rollstack. Every `/reports/{id}` endpoint works on it.\n- `GoogleSlides`, `GoogleDocs`, `MicrosoftPowerPoint`, `MicrosoftWord`: a file in Google Drive or OneDrive that Rollstack updates with its visualizations.\n- `UploadedPPTXFile`: a PowerPoint file uploaded to Rollstack, which it updates the same way.\n- `Email`: an email report, whose visualizations Rollstack sends in an email.\n\nOn a report that isn't a `SlideDeck`, only `getReport`, `updateReport`, `deleteReport`, `shareReport`, `unshareReport`, `getReportSchedules`, `updateReportSchedules`, `startReportRun`, `getReportRun` and `cancelReportRun` work. The other `/reports/{id}` endpoints take `SlideDeck` reports only, as their `id` says, and return `400`."},"name":{"type":"string","description":"Name of the report, as members see it in Rollstack. Change it with `updateReport`."},"folderId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The folder the report is in, by its `id` in `listFolders`. `null` when the report is at the top level, outside any folder."},"owner":{"type":"object","properties":{"id":{"type":"number","description":"The owner's user id, the same as their `id` in `listMembers`."},"name":{"type":"string","description":"The owner's name, as shown in Rollstack."},"email":{"type":"string","description":"The owner's email address. Rollstack emails this address when a scheduled run of the report fails, while `notifyOnFailure` is `true`."}},"required":["id","name","email"],"additionalProperties":false,"description":"The member who owns the report: whoever created it, unless ownership has since been transferred, in the app or with `transferReportOwnership`. Only the owner can delete the report."},"permission":{"anyOf":[{"type":"string","enum":["view","comment","edit"]},{"type":"null"}],"description":"Your access to the report, as the user the API key belongs to. `view` lets you open and export it, and see its datasheets, runs, schedules and email setup. `comment` also lets you add, reply to and resolve comments on its slides. `edit` also lets you change it: rename or move it, chat with the slides agent about it, add datasheets and read their data, start runs, set its schedules and email, send its email, and share it. It's never `null` here, since the API only returns reports you can at least view."},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The report's timezone, such as `America/New_York`. The slides agent uses it to tell today's date, and the report's emails show the time of its last successful update (`{{last_updated_at}}`) in it. On a report that updates a file, such as a Google Slides presentation, it's also the timezone of the file's date variables, unless the organization's `timezone` replaces it. Schedules don't use it: each has its own `timezone`. `null` when the report has none, in which case the slides agent uses UTC. Reports created with `createReport` start with the organization's `timezone` from `getOrganization`, if it has one."},"notifyOnFailure":{"type":"boolean","description":"Whether Rollstack emails the report's owner when a scheduled run fails or some of its datasheets, or a file's visualizations, fail to refresh, copying everyone in `notificationMailingList`. Runs started in the app or with `startReportRun` never send this email. New reports start with `true`."},"lastSyncedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the report's latest run ended, whatever its outcome. `null` if the report has never run."},"lastSuccessfulUpdateAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the report's latest fully successful run ended: one that refreshed every datasheet it ran on, or every visualization on a report that updates a file, with none failing. Runs with nothing to refresh don't count. The report's emails show this time as `{{last_updated_at}}`. `null` until the report has had such a run."},"lastRunStatus":{"anyOf":[{"type":"string","enum":["running","completed","failed","cancelled","timed_out"]},{"type":"null"}],"description":"How the report's latest run ended. `completed`: it finished, even if some datasheets or visualizations failed to refresh or it had none to refresh; on a `SlideDeck` report, `listReportDatasheets` shows each datasheet's `error`. `failed`: it stopped on an error, or none of its datasheets or visualizations could be refreshed. `cancelled`: it was stopped before it finished, for example with `cancelReportRun`. `null` if the report has never run. `running` and `timed_out` never appear here: check `running` to see whether a run is in progress."},"running":{"type":"boolean","description":"Whether a run of the report is in progress, whoever started it, such as you with `startReportRun`, a member in the app, or one of its schedules. While it's `true`, `startReportRun` returns that run instead of starting another."},"appUrl":{"type":"string","format":"uri","description":"Link that opens the report in Rollstack."},"createdAt":{"description":"When the report was created. `listReports` returns the newest first.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the report's details last changed, such as its name, folder or owner, or the outcome of its latest run.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"notificationMailingList":{"type":"array","items":{"type":"string"},"description":"Email addresses Rollstack copies when it emails the owner about a failed scheduled run, while `notifyOnFailure` is `true`. Change the list with `updateReport`."},"schedules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the schedule. `updateReportSchedules` replaces every schedule, so the ids change each time you call it."},"frequency":{"type":"string","enum":["daily","weekly","monthly","quarterly","hourly","yearly"],"description":"How often the schedule runs. `hourly` runs every day at each time in `selectedTimes`. `daily`, `weekly`, `monthly` and `quarterly` run whenever `cronExpression` fires; those made in the app run every day, on chosen weekdays, on chosen days of the month, or every three months, respectively. `yearly` can't be set through the API or the app, and also runs on `cronExpression`."},"cronExpression":{"type":"string","description":"When the schedule runs, as a five-field cron expression (minute, hour, day of month, month, day of week) in the schedule's `timezone`. For an `hourly` schedule, Rollstack generates it from `selectedTimes` and runs the report at those times instead. Monthly schedules made in the app can use `L` and `#`, such as `0 9 L * *` (last day of the month) or `0 9 ? * 1#1` (first Monday)."},"selectedTimes":{"type":"array","items":{"type":"string"},"description":"The times of day an `hourly` schedule runs, every day, as 24-hour `HH:mm` in the schedule's `timezone`. Other frequencies don't use it; it's empty on those set through the API."},"startDate":{"description":"When the schedule starts: it never runs the report before this date and time. This is a local date and time in the schedule's `timezone`, written as if it were UTC: `2026-11-02T09:00:00Z` means 9:00 on November 2, 2026 in that timezone, not 9:00 UTC.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"endDate":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the schedule ends: it never runs the report after this date and time. `null` if the schedule never ends. Like `startDate`, this is a local date and time in the schedule's `timezone`, written as if it were UTC."},"timezone":{"type":"string","description":"The timezone the schedule runs in. Its run times (`cronExpression` or `selectedTimes`), `startDate` and `endDate` are all local times in this timezone, so a schedule set for 9:00 keeps running at 9:00 local time when daylight saving time starts or ends. Given as an IANA timezone name, such as `America/New_York`."},"nextRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the schedule will next run the report. `null` if it has no runs left before its `endDate`. Unlike `startDate` and `endDate`, this is an actual UTC time."}},"required":["id","frequency","cronExpression","selectedTimes","startDate","endDate","timezone","nextRunAt"],"additionalProperties":false},"description":"The report's schedules: when Rollstack runs the report on its own to update it with fresh data. Empty if it has none, in which case the report only runs when someone starts a run. Replace them with `updateReportSchedules`."},"sharedWith":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"number","description":"The member's user id. Pass it as `userId` to `shareReport` to change their access, or to `unshareReport` to remove it."},"email":{"type":"string","description":"The member's email address, as shown in Rollstack."},"name":{"type":"string","description":"The member's name, as shown in Rollstack."},"permission":{"type":"string","enum":["view","comment","edit"],"description":"What the member can do with the report. `view` lets them open, export and duplicate it. `comment` also lets them add, reply to and resolve comments on its slides. `edit` also lets them change its slides, data, schedules, email and other settings, run it, send its email, chat with the slides agent about it, and manage who it's shared with. Neither lets them delete the report or transfer its ownership."}},"required":["userId","email","name","permission"],"additionalProperties":false},"description":"Members the report is shared with directly, with their access. Members who can open it through its folder aren't listed. Change this list with `shareReport` and `unshareReport`."}},"required":["id","type","name","folderId","owner","permission","timezone","notifyOnFailure","lastSyncedAt","lastSuccessfulUpdateAt","lastRunStatus","running","appUrl","createdAt","updatedAt","notificationMailingList","schedules","sharedWith"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteReport","summary":"Delete report","description":"Deletes a report of any type. A report that updates a file, such as a Google Slides presentation, leaves its file where it is. Only its owner may.\n\nRequires the `slide_decks:write` scope.","tags":["Reports"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`.","schema":{"type":"string","description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`."}}],"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/transfer-ownership":{"post":{"operationId":"transferReportOwnership","summary":"Transfer ownership","description":"Makes a member of the organization the owner of a report. Only its owner may, and keeps edit access.\n\nRequires the `slide_decks:write` scope.","tags":["Reports"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"newOwnerId":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The member who becomes the report's owner, by user id: their `id` in `listMembers`, or their `userId` in the report's `sharedWith`. They must be an active member of the organization other than you. The previous owner keeps `edit` access to the report, and the new owner is notified.","examples":[1042]}},"required":["newOwnerId"],"additionalProperties":false}}}},"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/messages/{messageId}":{"get":{"operationId":"getReportMessage","summary":"Get slides agent message","description":"A message to the slides agent and its replies. Waits up to waitSeconds for the message to finish and answers as soon as it does, so call it again while the status is queued or running. A clarification reply asks questions: ask the user, then send the options they pick as answers in a new message on the same chat. A proposal reply changes nothing until it is approved: show the user what its proposal changes, then approve or reject it as they decide. Only the user who sent the message may read it, while they can edit the report.\n\nRequires the `slide_decks:read` scope.","tags":["Chat"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}},{"name":"messageId","in":"path","required":true,"description":"The message to the slides agent: the `messageId` that `sendReportMessage` returned. Only the user who sent the message can read, cancel or decide its proposals, and only while they can edit the report.","schema":{"type":"string","description":"The message to the slides agent: the `messageId` that `sendReportMessage` returned. Only the user who sent the message can read, cancel or decide its proposals, and only while they can edit the report."}},{"name":"waitSeconds","in":"query","required":false,"description":"How long this call waits for the work to finish, in seconds: the message to the slides agent on `getReportMessage`, the run on `getReportRun`. It returns as soon as the work is done, or as things stand once the time is up, so call it again while `status` is still `queued` or `running`. `0` returns at once. Defaults to `20`; at most `30`.","schema":{"default":20,"description":"How long this call waits for the work to finish, in seconds: the message to the slides agent on `getReportMessage`, the run on `getReportRun`. It returns as soon as the work is done, or as things stand once the time is up, so call it again while `status` is still `queued` or `running`. `0` returns at once. Defaults to `20`; at most `30`.","type":"integer","minimum":0,"maximum":30}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"chatId":{"type":"string","description":"Identifies the chat the message is in, which also shows in your chat history on the report in the app. Pass it as `chatId` to `sendReportMessage` to continue the conversation, for example to answer a `clarification` reply."},"messageId":{"type":"string","description":"Identifies your message to the slides agent. Pass it as `messageId` to `getReportMessage` to follow its progress and read the agent's replies, or to `cancelReportMessage` to stop it."},"status":{"type":"string","enum":["queued","running","completed","failed","cancelled"],"description":"Where the message stands. `sendReportMessage` always returns `queued` or `running`.\n\n- `queued`: the agent is still replying to an earlier message of the same chat; this one starts once that reply is finished.\n- `running`: the slides agent is working on it. While other chats keep the agent busy on this report, it can first wait here for its turn.\n- `completed`: every reply is finished; `getReportMessage` lists them in `replies`.\n- `failed`: at least one of its replies failed.\n- `cancelled`: it was stopped while running, for example with `cancelReportMessage` or the stop button in the app. Cancelling a `queued` message removes it from the chat instead, so it is no longer found."},"appUrl":{"type":"string","format":"uri","description":"Link to the report in Rollstack, with this chat open, where you can follow the conversation and review the changes the agent made."},"stage":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the slides agent is doing right now, in the words the chat in the app shows, such as `Understanding your request`, `Refreshing data`, `Design` or `Finishing up`. Use it to show progress while `status` is `running`. `null` when no step is under way: while the message is `queued`, before the agent's first step, and once the message is finished."},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"When you sent the message to the slides agent."},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"When the message or any of its replies last changed, for example as the agent reports progress or finishes a reply."},"replies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Identifies the reply. It stays the same from `running` until the reply is finished, so you can follow each reply across calls."},"status":{"type":"string","enum":["running","completed","failed","cancelled"],"description":"Where this reply stands. `running` while the agent works on it or it waits its turn; on a `datasheet_filters_proposal`, until Rollstack has applied the filters. `completed` once the reply is finished: `type` says what it is. `failed` when the agent couldn't finish it, never got to it because an earlier part failed or was stopped, or the filters couldn't be applied. `cancelled` when it was stopped, for example with `cancelReportMessage` or the stop button in the app."},"type":{"anyOf":[{"type":"string","enum":["result","partial_result","clarification","answer","settings_proposal","proposal_applied","email_send_proposal","datasheet_filters_proposal","report_proposal"]},{"type":"null"}],"description":"What the reply is, which tells you what to do next. `null` while the agent is still working on it, and when it failed or was stopped.\n\n- `result`: the agent changed the report, and the changes are already saved. `changedSlideIds` lists the slides it added or changed; you can review or revert the changes in the app.\n- `partial_result`: the same as `result`, on replies written by an earlier version of the slides agent.\n- `clarification`: the agent needs more from you before it goes on. Answer its `questions`, or the question in `content` when there are none, in the next message on the same chat.\n- `answer`: the agent replied in `content` without changing the report, for example to a question about the report or about how Rollstack works.\n- `datasheet_filters_proposal`: the agent changes the values of filters that some of the report's datasheets apply when they read their source. For a message sent through the API, Rollstack applies them right away, without approval in the app. If your request needed more than that, it then goes on by itself as a new message in the same chat, unless you send one there first; that message isn't in these `replies`, so follow it in the app.\n- `settings_proposal`, `email_send_proposal`: a change to the report's update schedules, email settings, email template or parameters, or sending the report by email. Nothing changes until it is approved: show the user what `proposal` changes, then approve it with `approveReportMessageProposal` or reject it with `rejectReportMessageProposal`, as they decide. It can also be decided in the app. The agent makes one for a message sent through the API only when your API key has the scope the change needs.\n- `report_proposal`: a change elsewhere in Rollstack, such as to reports, folders or members. The agent doesn't make them for messages sent through the API.\n- `proposal_applied`: a note the chat in the app adds once a proposal is decided. It is never listed in `replies`."},"content":{"type":"string","description":"The reply's text, as the chat in the app shows it: what the agent did, its answer, or its questions. Empty until the agent has written it. When the reply failed or was stopped, it says so. Can contain Markdown."},"questions":{"description":"On a `clarification` reply: the multiple-choice questions the agent needs answered before it goes on. Send the options picked as `answers` in the next message on the same chat, or answer in your own words in `content`. Absent on other replies, and on a clarification that asks its question only in `content`.","type":"array","items":{"type":"object","properties":{"question":{"type":"string","description":"The question the agent is asking, as the chat in the app shows it."},"header":{"type":"string","description":"A short label for the question, such as `Chart type`, shown before it in the app. Send it back unchanged, with `question`, when you answer."},"multiSelect":{"type":"boolean","description":"Whether more than one option can be picked. When `true`, the app shows the options as checkboxes; when `false`, as a single choice, so answer with one option."},"options":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","description":"The option's text, as shown in the app. Send it back in `answers` to pick this option. The agent may mark the option it recommends with `(Recommended)`, which you can keep or drop."},"description":{"description":"What picking this option means, shown under its label in the app.","type":"string"},"value":{"description":"Set when the option offers data the agent found: a connection for the agent to search next, or a dashboard, table or spreadsheet that Rollstack adds to the report as a datasheet when you pick the option. It isn't shown in the app, and you don't send it back: picking the option by its `label` in the next message on the same chat is enough.","type":"string"}},"required":["label"],"additionalProperties":false},"description":"The options to choose from. Answer with the `label` of each one picked."}},"required":["question","header","multiSelect","options"],"additionalProperties":false}},"changedSlideIds":{"description":"On a `result` or `partial_result` reply: the slides the agent added or changed, in report order. Slides it deleted aren't listed. Pass them as `slideIds` to `getReportSlideImages` to check how they look, or to `getReportContent` to read them.","type":"array","items":{"type":"string"}},"proposal":{"description":"On a `settings_proposal` or `email_send_proposal` reply: what the proposal changes, or the email it sends, and where it stands. Absent on other replies.","anyOf":[{"type":"object","properties":{"status":{"type":"string","enum":["proposed","applied","rejected","superseded","conflict","failed"],"description":"`proposed` while it waits for the user to decide. `applied` once approved and applied, `rejected` once rejected. `superseded` when a later proposal in the chat replaced it. `conflict` when the report changed after it was proposed, so approving it applied nothing, and `failed` when applying it failed."},"changes":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"parameters.create"},"after":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"filters":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"dashboardName":{"type":"string"}},"required":["name","dashboardName"],"additionalProperties":false}},"datasheets":{"default":[],"type":"array","items":{"type":"string"}},"datasheetCount":{"type":"integer","minimum":0,"maximum":9007199254740991},"unlinkedDatasheets":{"type":"array","items":{"type":"string"}}},"required":["name","value","filters","datasheets","datasheetCount","unlinkedDatasheets"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"parameters.update"},"before":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"filters":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"dashboardName":{"type":"string"}},"required":["name","dashboardName"],"additionalProperties":false}},"datasheets":{"default":[],"type":"array","items":{"type":"string"}},"datasheetCount":{"type":"integer","minimum":0,"maximum":9007199254740991},"unlinkedDatasheets":{"type":"array","items":{"type":"string"}}},"required":["name","value","filters","datasheets","datasheetCount","unlinkedDatasheets"],"additionalProperties":false},"after":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"filters":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"dashboardName":{"type":"string"}},"required":["name","dashboardName"],"additionalProperties":false}},"datasheets":{"default":[],"type":"array","items":{"type":"string"}},"datasheetCount":{"type":"integer","minimum":0,"maximum":9007199254740991},"unlinkedDatasheets":{"type":"array","items":{"type":"string"}}},"required":["name","value","filters","datasheets","datasheetCount","unlinkedDatasheets"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"parameters.delete"},"before":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"filters":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"dashboardName":{"type":"string"}},"required":["name","dashboardName"],"additionalProperties":false}},"datasheets":{"default":[],"type":"array","items":{"type":"string"}},"datasheetCount":{"type":"integer","minimum":0,"maximum":9007199254740991},"unlinkedDatasheets":{"type":"array","items":{"type":"string"}}},"required":["name","value","filters","datasheets","datasheetCount","unlinkedDatasheets"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"parameters.setDatasheetLinked"},"parameterName":{"type":"string"},"filterName":{"type":"string"},"datasheetName":{"type":"string"},"isLinked":{"type":"boolean"},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","parameterName","filterName","datasheetName","isLinked","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.template.create"},"before":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"after":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"impact":{"anyOf":[{"type":"object","properties":{"consumers":{"type":"array","items":{"type":"string"}},"anonymousCount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["consumers","anonymousCount"],"additionalProperties":false},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","impact","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.template.update"},"before":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"after":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"impact":{"anyOf":[{"type":"object","properties":{"consumers":{"type":"array","items":{"type":"string"}},"anonymousCount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["consumers","anonymousCount"],"additionalProperties":false},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","impact","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.template.select"},"before":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"after":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"impact":{"anyOf":[{"type":"object","properties":{"consumers":{"type":"array","items":{"type":"string"}},"anonymousCount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["consumers","anonymousCount"],"additionalProperties":false},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","impact","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.template.reset"},"before":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"after":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"impact":{"anyOf":[{"type":"object","properties":{"consumers":{"type":"array","items":{"type":"string"}},"anonymousCount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["consumers","anonymousCount"],"additionalProperties":false},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","impact","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"schedule.add"},"after":{"type":"object","properties":{"frequency":{"type":"string"},"recurrence":{"type":"string"},"timezone":{"type":"string"},"startDate":{"type":"string"},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"syncNames":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["frequency","recurrence","timezone","startDate","endDate","syncNames","nextRunAt"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"schedule.remove"},"before":{"type":"object","properties":{"frequency":{"type":"string"},"recurrence":{"type":"string"},"timezone":{"type":"string"},"startDate":{"type":"string"},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"syncNames":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["frequency","recurrence","timezone","startDate","endDate","syncNames","nextRunAt"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"schedule.modify"},"before":{"type":"object","properties":{"frequency":{"type":"string"},"recurrence":{"type":"string"},"timezone":{"type":"string"},"startDate":{"type":"string"},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"syncNames":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["frequency","recurrence","timezone","startDate","endDate","syncNames","nextRunAt"],"additionalProperties":false},"after":{"type":"object","properties":{"frequency":{"type":"string"},"recurrence":{"type":"string"},"timezone":{"type":"string"},"startDate":{"type":"string"},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"syncNames":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["frequency","recurrence","timezone","startDate","endDate","syncNames","nextRunAt"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.config.update"},"before":{"anyOf":[{"type":"object","properties":{"trigger":{"type":"string","enum":["all","none","scheduled"]},"sharingFormat":{"type":"string","enum":["link","pdf","ppt","cloudLink"]},"sendAttachmentAsLink":{"type":"boolean"},"sender":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"}},"required":["id","label"],"additionalProperties":false},{"type":"null"}]}},"required":["trigger","sharingFormat","sendAttachmentAsLink","sender"],"additionalProperties":false},{"type":"null"}]},"after":{"type":"object","properties":{"trigger":{"type":"string","enum":["all","none","scheduled"]},"sharingFormat":{"type":"string","enum":["link","pdf","ppt","cloudLink"]},"sendAttachmentAsLink":{"type":"boolean"},"sender":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"}},"required":["id","label"],"additionalProperties":false},{"type":"null"}]}},"required":["trigger","sharingFormat","sendAttachmentAsLink","sender"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.recipients.update"},"before":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string"}},"cc":{"type":"array","items":{"type":"string"}},"bcc":{"type":"array","items":{"type":"string"}},"replyTo":{"type":"array","items":{"type":"string"}},"id":{"type":"string"},"label":{"type":"string"}},"required":["to","cc","bcc","replyTo","id","label"],"additionalProperties":false},"after":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string"}},"cc":{"type":"array","items":{"type":"string"}},"bcc":{"type":"array","items":{"type":"string"}},"replyTo":{"type":"array","items":{"type":"string"}},"id":{"type":"string"},"label":{"type":"string"}},"required":["to","cc","bcc","replyTo","id","label"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.recipients.createGroup"},"after":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string"}},"cc":{"type":"array","items":{"type":"string"}},"bcc":{"type":"array","items":{"type":"string"}},"replyTo":{"type":"array","items":{"type":"string"}}},"required":["to","cc","bcc","replyTo"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","after","warnings"],"additionalProperties":false}]},"description":"What approving it changes, as the approval card in the app shows it: one entry per change, with the setting before and after it. `warnings` point out what the user should know before approving, such as a schedule that never runs."}},"required":["status","changes"],"additionalProperties":false},{"type":"object","properties":{"status":{"type":"string","enum":["awaiting_confirmation","cancelled","superseded","queued","sending","sent","partially_sent","failed","unconfirmed"],"description":"`awaiting_confirmation` while it waits for the user to decide, `cancelled` once rejected, and `superseded` when a later proposal in the chat replaced it. Once approved: `queued` and `sending` until every email is handed to the email provider, then `sent`, `partially_sent` or `failed`. `unconfirmed` when Rollstack lost track of the send, so some emails may have gone out."},"recipients":{"type":"array","items":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string"}},"cc":{"type":"array","items":{"type":"string"}},"bcc":{"type":"array","items":{"type":"string"}},"replyTo":{"type":"array","items":{"type":"string"}},"id":{"type":"string"},"label":{"type":"string"}},"required":["to","cc","bcc","replyTo","id","label"],"additionalProperties":false},"description":"Who receives the report: one email per group, each with its own addresses."},"sharingFormat":{"type":"string","enum":["pdf","ppt"],"description":"The file sent: the report's visible slides as a PDF (`pdf`) or PowerPoint file (`ppt`)."},"sendAttachmentAsLink":{"type":"boolean","description":"Whether the file is behind a download button in the email instead of attached."},"counts":{"anyOf":[{"type":"object","properties":{"total":{"type":"integer","minimum":0,"maximum":9007199254740991},"sent":{"type":"integer","minimum":0,"maximum":9007199254740991},"failed":{"type":"integer","minimum":0,"maximum":9007199254740991},"unknown":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["total","sent","failed","unknown"],"additionalProperties":false},{"type":"null"}],"description":"How many emails were handed to the email provider, failed, or ended unknown. `null` until the send starts."}},"required":["status","recipients","sharingFormat","sendAttachmentAsLink","counts"],"additionalProperties":false}]}},"required":["id","status","type","content"],"additionalProperties":false},"description":"The slides agent's replies to this message, in order. The first one is listed, `running`, as soon as the message is sent. The agent can split a message that asks for several things into parts, each with its own reply; the message is finished only once every part is."}},"required":["chatId","messageId","status","appUrl","stage","createdAt","updatedAt","replies"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/messages":{"post":{"operationId":"sendReportMessage","summary":"Send message to slides agent","description":"Asks the slides agent to build or change a report, or to answer a question about it, as the app's chat does. Answers the message's id at once: follow it with getReportMessage. Without chatId the message starts a new chat, which shows in the user's chat history in the app. With it, the message continues that chat and waits its turn while a reply is still generating. Several chats on a report can generate at once; an agent working on a part of the report another chat is editing works on something else or says so. For slides built from your own data, a connected dashboard or a spreadsheet, upload the data with createDataset, find the dashboard with searchDashboards or the spreadsheet with searchSpreadsheets, add any of them with addReportDatasheets and pass the datasheet ids as datasheetIds. Only its editors may. At most 6 messages a minute per user.\n\nRequires the `slide_decks:run` scope.","tags":["Chat"],"x-scope":"slide_decks:run","security":[{"apiKey":[]},{"oauth2":["slide_decks:run"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"content":{"default":"","description":"Your message to the slides agent, as you would write it in the chat in the app: for example, slides to build or change, or a question about the report. On a report with no slides yet, the agent takes it as a request to build the report. Required unless you send `answers`; with them, it's sent after your answers as a note. At most 10,000 characters.","examples":["Add a slide comparing revenue by region"],"type":"string","maxLength":10000},"chatId":{"description":"The chat to continue: the `chatId` returned for an earlier message. The agent reads the chat's earlier messages as context, and if it's still replying in that chat, your message waits its turn (`queued`). If omitted, the message starts a new chat, which shows in your chat history on the report in the app. Must be one of your own chats on this report.","examples":["0e4c2b7a-9d1f-4a3b-8c5e-6f7a8b9c0d1e"],"type":"string"},"slideIds":{"description":"The slides your message is about, as when you select slides in the app before writing in the chat. The agent knows you selected them and uses the datasheets on them for your request. Slide ids come from `getReportContent`. 1 to 100 slides of this report.","minItems":1,"maxItems":100,"type":"array","items":{"type":"string","examples":["f1e2d3c4-b5a6-4978-8a1b-2c3d4e5f6a7b"]}},"datasheetIds":{"description":"Datasheets of this report for the agent to work from, on top of those on the slides in `slideIds`, as when you pick data in the chat in the app. To have the agent build slides from data you just added, pass the ids `addReportDatasheets` returned; for data already on the report, take them from `listReportDatasheets`. 1 to 100 datasheets of this report.","minItems":1,"maxItems":100,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","examples":["d7b9a1c3-e5f7-4a9b-8c1d-3e5f7a9b1c2d"]}},"answers":{"description":"Your answers to the questions of a `clarification` reply, as when you pick options in the chat in the app: one entry per question you answer. Send them as the next message on the same chat, by passing its `chatId`. When a picked option offers a dashboard, table or spreadsheet, Rollstack adds it to the report as a datasheet before the agent goes on. To add a note, send it in `content` with the answers.","minItems":1,"type":"array","items":{"type":"object","properties":{"header":{"type":"string","description":"The `header` of the question you're answering, copied unchanged from the `clarification` reply's `questions`.","examples":["Chart type"]},"question":{"type":"string","description":"The question you're answering, copied unchanged from the `clarification` reply's `questions`. With `header`, it tells Rollstack which question your picks are for.","examples":["Which chart should show revenue by region?"]},"answers":{"minItems":1,"type":"array","items":{"type":"string","examples":["Bar chart"]},"description":"The `label` of each option picked: one for a question whose `multiSelect` is `false`, one or more when it's `true`."}},"required":["header","question","answers"]}}},"additionalProperties":false}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"chatId":{"type":"string","description":"Identifies the chat the message is in, which also shows in your chat history on the report in the app. Pass it as `chatId` to `sendReportMessage` to continue the conversation, for example to answer a `clarification` reply."},"messageId":{"type":"string","description":"Identifies your message to the slides agent. Pass it as `messageId` to `getReportMessage` to follow its progress and read the agent's replies, or to `cancelReportMessage` to stop it."},"status":{"type":"string","enum":["queued","running","completed","failed","cancelled"],"description":"Where the message stands. `sendReportMessage` always returns `queued` or `running`.\n\n- `queued`: the agent is still replying to an earlier message of the same chat; this one starts once that reply is finished.\n- `running`: the slides agent is working on it. While other chats keep the agent busy on this report, it can first wait here for its turn.\n- `completed`: every reply is finished; `getReportMessage` lists them in `replies`.\n- `failed`: at least one of its replies failed.\n- `cancelled`: it was stopped while running, for example with `cancelReportMessage` or the stop button in the app. Cancelling a `queued` message removes it from the chat instead, so it is no longer found."},"appUrl":{"type":"string","format":"uri","description":"Link to the report in Rollstack, with this chat open, where you can follow the conversation and review the changes the agent made."}},"required":["chatId","messageId","status","appUrl"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/messages/{messageId}/replies/{replyId}/approve":{"post":{"operationId":"approveReportMessageProposal","summary":"Approve slides agent proposal","description":"Approves the proposal of a settings_proposal or email_send_proposal reply, as its Approve button in the app's chat does: Rollstack makes the change, or sends the email. Only approve what the user approved after seeing the reply's proposal. Answers the reply with the proposal's status: applied once the change is made, and queued for a send, which getReportMessage then follows through sending to sent, partially_sent, failed or unconfirmed, with its counts. Needs also slide_decks:email for an email change or send, and slide_decks:write for the rest. Approving a send answers 409 while the report is updating, such as after a filter change the same message asked for, and counts against the 5 email sends a minute, as sendReportEmail does. Only the user who sent the message may, while they can edit the report. A proposal already decided answers 409.\n\nRequires the `slide_decks:run` scope.","tags":["Chat"],"x-scope":"slide_decks:run","security":[{"apiKey":[]},{"oauth2":["slide_decks:run"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}},{"name":"messageId","in":"path","required":true,"description":"The message to the slides agent: the `messageId` that `sendReportMessage` returned. Only the user who sent the message can read, cancel or decide its proposals, and only while they can edit the report.","schema":{"type":"string","description":"The message to the slides agent: the `messageId` that `sendReportMessage` returned. Only the user who sent the message can read, cancel or decide its proposals, and only while they can edit the report."}},{"name":"replyId","in":"path","required":true,"description":"The reply that makes the proposal: the `id` of a `settings_proposal` or `email_send_proposal` reply that `getReportMessage` lists for the message.","schema":{"type":"string","description":"The reply that makes the proposal: the `id` of a `settings_proposal` or `email_send_proposal` reply that `getReportMessage` lists for the message."}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Identifies the reply. It stays the same from `running` until the reply is finished, so you can follow each reply across calls."},"status":{"type":"string","enum":["running","completed","failed","cancelled"],"description":"Where this reply stands. `running` while the agent works on it or it waits its turn; on a `datasheet_filters_proposal`, until Rollstack has applied the filters. `completed` once the reply is finished: `type` says what it is. `failed` when the agent couldn't finish it, never got to it because an earlier part failed or was stopped, or the filters couldn't be applied. `cancelled` when it was stopped, for example with `cancelReportMessage` or the stop button in the app."},"type":{"anyOf":[{"type":"string","enum":["result","partial_result","clarification","answer","settings_proposal","proposal_applied","email_send_proposal","datasheet_filters_proposal","report_proposal"]},{"type":"null"}],"description":"What the reply is, which tells you what to do next. `null` while the agent is still working on it, and when it failed or was stopped.\n\n- `result`: the agent changed the report, and the changes are already saved. `changedSlideIds` lists the slides it added or changed; you can review or revert the changes in the app.\n- `partial_result`: the same as `result`, on replies written by an earlier version of the slides agent.\n- `clarification`: the agent needs more from you before it goes on. Answer its `questions`, or the question in `content` when there are none, in the next message on the same chat.\n- `answer`: the agent replied in `content` without changing the report, for example to a question about the report or about how Rollstack works.\n- `datasheet_filters_proposal`: the agent changes the values of filters that some of the report's datasheets apply when they read their source. For a message sent through the API, Rollstack applies them right away, without approval in the app. If your request needed more than that, it then goes on by itself as a new message in the same chat, unless you send one there first; that message isn't in these `replies`, so follow it in the app.\n- `settings_proposal`, `email_send_proposal`: a change to the report's update schedules, email settings, email template or parameters, or sending the report by email. Nothing changes until it is approved: show the user what `proposal` changes, then approve it with `approveReportMessageProposal` or reject it with `rejectReportMessageProposal`, as they decide. It can also be decided in the app. The agent makes one for a message sent through the API only when your API key has the scope the change needs.\n- `report_proposal`: a change elsewhere in Rollstack, such as to reports, folders or members. The agent doesn't make them for messages sent through the API.\n- `proposal_applied`: a note the chat in the app adds once a proposal is decided. It is never listed in `replies`."},"content":{"type":"string","description":"The reply's text, as the chat in the app shows it: what the agent did, its answer, or its questions. Empty until the agent has written it. When the reply failed or was stopped, it says so. Can contain Markdown."},"questions":{"description":"On a `clarification` reply: the multiple-choice questions the agent needs answered before it goes on. Send the options picked as `answers` in the next message on the same chat, or answer in your own words in `content`. Absent on other replies, and on a clarification that asks its question only in `content`.","type":"array","items":{"type":"object","properties":{"question":{"type":"string","description":"The question the agent is asking, as the chat in the app shows it."},"header":{"type":"string","description":"A short label for the question, such as `Chart type`, shown before it in the app. Send it back unchanged, with `question`, when you answer."},"multiSelect":{"type":"boolean","description":"Whether more than one option can be picked. When `true`, the app shows the options as checkboxes; when `false`, as a single choice, so answer with one option."},"options":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","description":"The option's text, as shown in the app. Send it back in `answers` to pick this option. The agent may mark the option it recommends with `(Recommended)`, which you can keep or drop."},"description":{"description":"What picking this option means, shown under its label in the app.","type":"string"},"value":{"description":"Set when the option offers data the agent found: a connection for the agent to search next, or a dashboard, table or spreadsheet that Rollstack adds to the report as a datasheet when you pick the option. It isn't shown in the app, and you don't send it back: picking the option by its `label` in the next message on the same chat is enough.","type":"string"}},"required":["label"],"additionalProperties":false},"description":"The options to choose from. Answer with the `label` of each one picked."}},"required":["question","header","multiSelect","options"],"additionalProperties":false}},"changedSlideIds":{"description":"On a `result` or `partial_result` reply: the slides the agent added or changed, in report order. Slides it deleted aren't listed. Pass them as `slideIds` to `getReportSlideImages` to check how they look, or to `getReportContent` to read them.","type":"array","items":{"type":"string"}},"proposal":{"description":"On a `settings_proposal` or `email_send_proposal` reply: what the proposal changes, or the email it sends, and where it stands. Absent on other replies.","anyOf":[{"type":"object","properties":{"status":{"type":"string","enum":["proposed","applied","rejected","superseded","conflict","failed"],"description":"`proposed` while it waits for the user to decide. `applied` once approved and applied, `rejected` once rejected. `superseded` when a later proposal in the chat replaced it. `conflict` when the report changed after it was proposed, so approving it applied nothing, and `failed` when applying it failed."},"changes":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"parameters.create"},"after":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"filters":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"dashboardName":{"type":"string"}},"required":["name","dashboardName"],"additionalProperties":false}},"datasheets":{"default":[],"type":"array","items":{"type":"string"}},"datasheetCount":{"type":"integer","minimum":0,"maximum":9007199254740991},"unlinkedDatasheets":{"type":"array","items":{"type":"string"}}},"required":["name","value","filters","datasheets","datasheetCount","unlinkedDatasheets"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"parameters.update"},"before":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"filters":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"dashboardName":{"type":"string"}},"required":["name","dashboardName"],"additionalProperties":false}},"datasheets":{"default":[],"type":"array","items":{"type":"string"}},"datasheetCount":{"type":"integer","minimum":0,"maximum":9007199254740991},"unlinkedDatasheets":{"type":"array","items":{"type":"string"}}},"required":["name","value","filters","datasheets","datasheetCount","unlinkedDatasheets"],"additionalProperties":false},"after":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"filters":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"dashboardName":{"type":"string"}},"required":["name","dashboardName"],"additionalProperties":false}},"datasheets":{"default":[],"type":"array","items":{"type":"string"}},"datasheetCount":{"type":"integer","minimum":0,"maximum":9007199254740991},"unlinkedDatasheets":{"type":"array","items":{"type":"string"}}},"required":["name","value","filters","datasheets","datasheetCount","unlinkedDatasheets"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"parameters.delete"},"before":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"filters":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"dashboardName":{"type":"string"}},"required":["name","dashboardName"],"additionalProperties":false}},"datasheets":{"default":[],"type":"array","items":{"type":"string"}},"datasheetCount":{"type":"integer","minimum":0,"maximum":9007199254740991},"unlinkedDatasheets":{"type":"array","items":{"type":"string"}}},"required":["name","value","filters","datasheets","datasheetCount","unlinkedDatasheets"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"parameters.setDatasheetLinked"},"parameterName":{"type":"string"},"filterName":{"type":"string"},"datasheetName":{"type":"string"},"isLinked":{"type":"boolean"},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","parameterName","filterName","datasheetName","isLinked","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.template.create"},"before":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"after":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"impact":{"anyOf":[{"type":"object","properties":{"consumers":{"type":"array","items":{"type":"string"}},"anonymousCount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["consumers","anonymousCount"],"additionalProperties":false},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","impact","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.template.update"},"before":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"after":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"impact":{"anyOf":[{"type":"object","properties":{"consumers":{"type":"array","items":{"type":"string"}},"anonymousCount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["consumers","anonymousCount"],"additionalProperties":false},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","impact","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.template.select"},"before":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"after":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"impact":{"anyOf":[{"type":"object","properties":{"consumers":{"type":"array","items":{"type":"string"}},"anonymousCount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["consumers","anonymousCount"],"additionalProperties":false},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","impact","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.template.reset"},"before":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"after":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"impact":{"anyOf":[{"type":"object","properties":{"consumers":{"type":"array","items":{"type":"string"}},"anonymousCount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["consumers","anonymousCount"],"additionalProperties":false},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","impact","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"schedule.add"},"after":{"type":"object","properties":{"frequency":{"type":"string"},"recurrence":{"type":"string"},"timezone":{"type":"string"},"startDate":{"type":"string"},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"syncNames":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["frequency","recurrence","timezone","startDate","endDate","syncNames","nextRunAt"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"schedule.remove"},"before":{"type":"object","properties":{"frequency":{"type":"string"},"recurrence":{"type":"string"},"timezone":{"type":"string"},"startDate":{"type":"string"},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"syncNames":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["frequency","recurrence","timezone","startDate","endDate","syncNames","nextRunAt"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"schedule.modify"},"before":{"type":"object","properties":{"frequency":{"type":"string"},"recurrence":{"type":"string"},"timezone":{"type":"string"},"startDate":{"type":"string"},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"syncNames":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["frequency","recurrence","timezone","startDate","endDate","syncNames","nextRunAt"],"additionalProperties":false},"after":{"type":"object","properties":{"frequency":{"type":"string"},"recurrence":{"type":"string"},"timezone":{"type":"string"},"startDate":{"type":"string"},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"syncNames":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["frequency","recurrence","timezone","startDate","endDate","syncNames","nextRunAt"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.config.update"},"before":{"anyOf":[{"type":"object","properties":{"trigger":{"type":"string","enum":["all","none","scheduled"]},"sharingFormat":{"type":"string","enum":["link","pdf","ppt","cloudLink"]},"sendAttachmentAsLink":{"type":"boolean"},"sender":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"}},"required":["id","label"],"additionalProperties":false},{"type":"null"}]}},"required":["trigger","sharingFormat","sendAttachmentAsLink","sender"],"additionalProperties":false},{"type":"null"}]},"after":{"type":"object","properties":{"trigger":{"type":"string","enum":["all","none","scheduled"]},"sharingFormat":{"type":"string","enum":["link","pdf","ppt","cloudLink"]},"sendAttachmentAsLink":{"type":"boolean"},"sender":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"}},"required":["id","label"],"additionalProperties":false},{"type":"null"}]}},"required":["trigger","sharingFormat","sendAttachmentAsLink","sender"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.recipients.update"},"before":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string"}},"cc":{"type":"array","items":{"type":"string"}},"bcc":{"type":"array","items":{"type":"string"}},"replyTo":{"type":"array","items":{"type":"string"}},"id":{"type":"string"},"label":{"type":"string"}},"required":["to","cc","bcc","replyTo","id","label"],"additionalProperties":false},"after":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string"}},"cc":{"type":"array","items":{"type":"string"}},"bcc":{"type":"array","items":{"type":"string"}},"replyTo":{"type":"array","items":{"type":"string"}},"id":{"type":"string"},"label":{"type":"string"}},"required":["to","cc","bcc","replyTo","id","label"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.recipients.createGroup"},"after":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string"}},"cc":{"type":"array","items":{"type":"string"}},"bcc":{"type":"array","items":{"type":"string"}},"replyTo":{"type":"array","items":{"type":"string"}}},"required":["to","cc","bcc","replyTo"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","after","warnings"],"additionalProperties":false}]},"description":"What approving it changes, as the approval card in the app shows it: one entry per change, with the setting before and after it. `warnings` point out what the user should know before approving, such as a schedule that never runs."}},"required":["status","changes"],"additionalProperties":false},{"type":"object","properties":{"status":{"type":"string","enum":["awaiting_confirmation","cancelled","superseded","queued","sending","sent","partially_sent","failed","unconfirmed"],"description":"`awaiting_confirmation` while it waits for the user to decide, `cancelled` once rejected, and `superseded` when a later proposal in the chat replaced it. Once approved: `queued` and `sending` until every email is handed to the email provider, then `sent`, `partially_sent` or `failed`. `unconfirmed` when Rollstack lost track of the send, so some emails may have gone out."},"recipients":{"type":"array","items":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string"}},"cc":{"type":"array","items":{"type":"string"}},"bcc":{"type":"array","items":{"type":"string"}},"replyTo":{"type":"array","items":{"type":"string"}},"id":{"type":"string"},"label":{"type":"string"}},"required":["to","cc","bcc","replyTo","id","label"],"additionalProperties":false},"description":"Who receives the report: one email per group, each with its own addresses."},"sharingFormat":{"type":"string","enum":["pdf","ppt"],"description":"The file sent: the report's visible slides as a PDF (`pdf`) or PowerPoint file (`ppt`)."},"sendAttachmentAsLink":{"type":"boolean","description":"Whether the file is behind a download button in the email instead of attached."},"counts":{"anyOf":[{"type":"object","properties":{"total":{"type":"integer","minimum":0,"maximum":9007199254740991},"sent":{"type":"integer","minimum":0,"maximum":9007199254740991},"failed":{"type":"integer","minimum":0,"maximum":9007199254740991},"unknown":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["total","sent","failed","unknown"],"additionalProperties":false},{"type":"null"}],"description":"How many emails were handed to the email provider, failed, or ended unknown. `null` until the send starts."}},"required":["status","recipients","sharingFormat","sendAttachmentAsLink","counts"],"additionalProperties":false}]}},"required":["id","status","type","content"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/messages/{messageId}/cancel":{"post":{"operationId":"cancelReportMessage","summary":"Cancel slides agent message","description":"Stops a message to the slides agent: a queued one leaves the queue, and a running one stops. A finished one stays as it is. Only the user who sent it may.\n\nRequires the `slide_decks:run` scope.","tags":["Chat"],"x-scope":"slide_decks:run","security":[{"apiKey":[]},{"oauth2":["slide_decks:run"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}},{"name":"messageId","in":"path","required":true,"description":"The message to the slides agent: the `messageId` that `sendReportMessage` returned. Only the user who sent the message can read, cancel or decide its proposals, and only while they can edit the report.","schema":{"type":"string","description":"The message to the slides agent: the `messageId` that `sendReportMessage` returned. Only the user who sent the message can read, cancel or decide its proposals, and only while they can edit the report."}}],"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/messages/{messageId}/replies/{replyId}/reject":{"post":{"operationId":"rejectReportMessageProposal","summary":"Reject slides agent proposal","description":"Rejects the proposal of a settings_proposal or email_send_proposal reply, as its Reject button in the app's chat does: nothing changes. Answers the reply with the proposal's status, rejected for a change and cancelled for an email send. Only the user who sent the message may, while they can edit the report. A proposal already decided answers 409.\n\nRequires the `slide_decks:run` scope.","tags":["Chat"],"x-scope":"slide_decks:run","security":[{"apiKey":[]},{"oauth2":["slide_decks:run"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}},{"name":"messageId","in":"path","required":true,"description":"The message to the slides agent: the `messageId` that `sendReportMessage` returned. Only the user who sent the message can read, cancel or decide its proposals, and only while they can edit the report.","schema":{"type":"string","description":"The message to the slides agent: the `messageId` that `sendReportMessage` returned. Only the user who sent the message can read, cancel or decide its proposals, and only while they can edit the report."}},{"name":"replyId","in":"path","required":true,"description":"The reply that makes the proposal: the `id` of a `settings_proposal` or `email_send_proposal` reply that `getReportMessage` lists for the message.","schema":{"type":"string","description":"The reply that makes the proposal: the `id` of a `settings_proposal` or `email_send_proposal` reply that `getReportMessage` lists for the message."}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Identifies the reply. It stays the same from `running` until the reply is finished, so you can follow each reply across calls."},"status":{"type":"string","enum":["running","completed","failed","cancelled"],"description":"Where this reply stands. `running` while the agent works on it or it waits its turn; on a `datasheet_filters_proposal`, until Rollstack has applied the filters. `completed` once the reply is finished: `type` says what it is. `failed` when the agent couldn't finish it, never got to it because an earlier part failed or was stopped, or the filters couldn't be applied. `cancelled` when it was stopped, for example with `cancelReportMessage` or the stop button in the app."},"type":{"anyOf":[{"type":"string","enum":["result","partial_result","clarification","answer","settings_proposal","proposal_applied","email_send_proposal","datasheet_filters_proposal","report_proposal"]},{"type":"null"}],"description":"What the reply is, which tells you what to do next. `null` while the agent is still working on it, and when it failed or was stopped.\n\n- `result`: the agent changed the report, and the changes are already saved. `changedSlideIds` lists the slides it added or changed; you can review or revert the changes in the app.\n- `partial_result`: the same as `result`, on replies written by an earlier version of the slides agent.\n- `clarification`: the agent needs more from you before it goes on. Answer its `questions`, or the question in `content` when there are none, in the next message on the same chat.\n- `answer`: the agent replied in `content` without changing the report, for example to a question about the report or about how Rollstack works.\n- `datasheet_filters_proposal`: the agent changes the values of filters that some of the report's datasheets apply when they read their source. For a message sent through the API, Rollstack applies them right away, without approval in the app. If your request needed more than that, it then goes on by itself as a new message in the same chat, unless you send one there first; that message isn't in these `replies`, so follow it in the app.\n- `settings_proposal`, `email_send_proposal`: a change to the report's update schedules, email settings, email template or parameters, or sending the report by email. Nothing changes until it is approved: show the user what `proposal` changes, then approve it with `approveReportMessageProposal` or reject it with `rejectReportMessageProposal`, as they decide. It can also be decided in the app. The agent makes one for a message sent through the API only when your API key has the scope the change needs.\n- `report_proposal`: a change elsewhere in Rollstack, such as to reports, folders or members. The agent doesn't make them for messages sent through the API.\n- `proposal_applied`: a note the chat in the app adds once a proposal is decided. It is never listed in `replies`."},"content":{"type":"string","description":"The reply's text, as the chat in the app shows it: what the agent did, its answer, or its questions. Empty until the agent has written it. When the reply failed or was stopped, it says so. Can contain Markdown."},"questions":{"description":"On a `clarification` reply: the multiple-choice questions the agent needs answered before it goes on. Send the options picked as `answers` in the next message on the same chat, or answer in your own words in `content`. Absent on other replies, and on a clarification that asks its question only in `content`.","type":"array","items":{"type":"object","properties":{"question":{"type":"string","description":"The question the agent is asking, as the chat in the app shows it."},"header":{"type":"string","description":"A short label for the question, such as `Chart type`, shown before it in the app. Send it back unchanged, with `question`, when you answer."},"multiSelect":{"type":"boolean","description":"Whether more than one option can be picked. When `true`, the app shows the options as checkboxes; when `false`, as a single choice, so answer with one option."},"options":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","description":"The option's text, as shown in the app. Send it back in `answers` to pick this option. The agent may mark the option it recommends with `(Recommended)`, which you can keep or drop."},"description":{"description":"What picking this option means, shown under its label in the app.","type":"string"},"value":{"description":"Set when the option offers data the agent found: a connection for the agent to search next, or a dashboard, table or spreadsheet that Rollstack adds to the report as a datasheet when you pick the option. It isn't shown in the app, and you don't send it back: picking the option by its `label` in the next message on the same chat is enough.","type":"string"}},"required":["label"],"additionalProperties":false},"description":"The options to choose from. Answer with the `label` of each one picked."}},"required":["question","header","multiSelect","options"],"additionalProperties":false}},"changedSlideIds":{"description":"On a `result` or `partial_result` reply: the slides the agent added or changed, in report order. Slides it deleted aren't listed. Pass them as `slideIds` to `getReportSlideImages` to check how they look, or to `getReportContent` to read them.","type":"array","items":{"type":"string"}},"proposal":{"description":"On a `settings_proposal` or `email_send_proposal` reply: what the proposal changes, or the email it sends, and where it stands. Absent on other replies.","anyOf":[{"type":"object","properties":{"status":{"type":"string","enum":["proposed","applied","rejected","superseded","conflict","failed"],"description":"`proposed` while it waits for the user to decide. `applied` once approved and applied, `rejected` once rejected. `superseded` when a later proposal in the chat replaced it. `conflict` when the report changed after it was proposed, so approving it applied nothing, and `failed` when applying it failed."},"changes":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"parameters.create"},"after":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"filters":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"dashboardName":{"type":"string"}},"required":["name","dashboardName"],"additionalProperties":false}},"datasheets":{"default":[],"type":"array","items":{"type":"string"}},"datasheetCount":{"type":"integer","minimum":0,"maximum":9007199254740991},"unlinkedDatasheets":{"type":"array","items":{"type":"string"}}},"required":["name","value","filters","datasheets","datasheetCount","unlinkedDatasheets"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"parameters.update"},"before":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"filters":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"dashboardName":{"type":"string"}},"required":["name","dashboardName"],"additionalProperties":false}},"datasheets":{"default":[],"type":"array","items":{"type":"string"}},"datasheetCount":{"type":"integer","minimum":0,"maximum":9007199254740991},"unlinkedDatasheets":{"type":"array","items":{"type":"string"}}},"required":["name","value","filters","datasheets","datasheetCount","unlinkedDatasheets"],"additionalProperties":false},"after":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"filters":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"dashboardName":{"type":"string"}},"required":["name","dashboardName"],"additionalProperties":false}},"datasheets":{"default":[],"type":"array","items":{"type":"string"}},"datasheetCount":{"type":"integer","minimum":0,"maximum":9007199254740991},"unlinkedDatasheets":{"type":"array","items":{"type":"string"}}},"required":["name","value","filters","datasheets","datasheetCount","unlinkedDatasheets"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"parameters.delete"},"before":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"filters":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"dashboardName":{"type":"string"}},"required":["name","dashboardName"],"additionalProperties":false}},"datasheets":{"default":[],"type":"array","items":{"type":"string"}},"datasheetCount":{"type":"integer","minimum":0,"maximum":9007199254740991},"unlinkedDatasheets":{"type":"array","items":{"type":"string"}}},"required":["name","value","filters","datasheets","datasheetCount","unlinkedDatasheets"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"parameters.setDatasheetLinked"},"parameterName":{"type":"string"},"filterName":{"type":"string"},"datasheetName":{"type":"string"},"isLinked":{"type":"boolean"},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","parameterName","filterName","datasheetName","isLinked","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.template.create"},"before":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"after":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"impact":{"anyOf":[{"type":"object","properties":{"consumers":{"type":"array","items":{"type":"string"}},"anonymousCount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["consumers","anonymousCount"],"additionalProperties":false},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","impact","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.template.update"},"before":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"after":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"impact":{"anyOf":[{"type":"object","properties":{"consumers":{"type":"array","items":{"type":"string"}},"anonymousCount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["consumers","anonymousCount"],"additionalProperties":false},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","impact","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.template.select"},"before":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"after":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"impact":{"anyOf":[{"type":"object","properties":{"consumers":{"type":"array","items":{"type":"string"}},"anonymousCount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["consumers","anonymousCount"],"additionalProperties":false},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","impact","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.template.reset"},"before":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"after":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"type":"string"},"content":{"type":"string"},"button":{"type":"object","properties":{"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"bgColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["textColor","bgColor"],"additionalProperties":false},"editable":{"type":"boolean"}},"required":["id","name","subject","content","button","editable"],"additionalProperties":false},{"type":"null"}]},"impact":{"anyOf":[{"type":"object","properties":{"consumers":{"type":"array","items":{"type":"string"}},"anonymousCount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["consumers","anonymousCount"],"additionalProperties":false},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","impact","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"schedule.add"},"after":{"type":"object","properties":{"frequency":{"type":"string"},"recurrence":{"type":"string"},"timezone":{"type":"string"},"startDate":{"type":"string"},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"syncNames":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["frequency","recurrence","timezone","startDate","endDate","syncNames","nextRunAt"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"schedule.remove"},"before":{"type":"object","properties":{"frequency":{"type":"string"},"recurrence":{"type":"string"},"timezone":{"type":"string"},"startDate":{"type":"string"},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"syncNames":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["frequency","recurrence","timezone","startDate","endDate","syncNames","nextRunAt"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"schedule.modify"},"before":{"type":"object","properties":{"frequency":{"type":"string"},"recurrence":{"type":"string"},"timezone":{"type":"string"},"startDate":{"type":"string"},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"syncNames":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["frequency","recurrence","timezone","startDate","endDate","syncNames","nextRunAt"],"additionalProperties":false},"after":{"type":"object","properties":{"frequency":{"type":"string"},"recurrence":{"type":"string"},"timezone":{"type":"string"},"startDate":{"type":"string"},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"syncNames":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["frequency","recurrence","timezone","startDate","endDate","syncNames","nextRunAt"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.config.update"},"before":{"anyOf":[{"type":"object","properties":{"trigger":{"type":"string","enum":["all","none","scheduled"]},"sharingFormat":{"type":"string","enum":["link","pdf","ppt","cloudLink"]},"sendAttachmentAsLink":{"type":"boolean"},"sender":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"}},"required":["id","label"],"additionalProperties":false},{"type":"null"}]}},"required":["trigger","sharingFormat","sendAttachmentAsLink","sender"],"additionalProperties":false},{"type":"null"}]},"after":{"type":"object","properties":{"trigger":{"type":"string","enum":["all","none","scheduled"]},"sharingFormat":{"type":"string","enum":["link","pdf","ppt","cloudLink"]},"sendAttachmentAsLink":{"type":"boolean"},"sender":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"}},"required":["id","label"],"additionalProperties":false},{"type":"null"}]}},"required":["trigger","sharingFormat","sendAttachmentAsLink","sender"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.recipients.update"},"before":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string"}},"cc":{"type":"array","items":{"type":"string"}},"bcc":{"type":"array","items":{"type":"string"}},"replyTo":{"type":"array","items":{"type":"string"}},"id":{"type":"string"},"label":{"type":"string"}},"required":["to","cc","bcc","replyTo","id","label"],"additionalProperties":false},"after":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string"}},"cc":{"type":"array","items":{"type":"string"}},"bcc":{"type":"array","items":{"type":"string"}},"replyTo":{"type":"array","items":{"type":"string"}},"id":{"type":"string"},"label":{"type":"string"}},"required":["to","cc","bcc","replyTo","id","label"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","before","after","warnings"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email.recipients.createGroup"},"after":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string"}},"cc":{"type":"array","items":{"type":"string"}},"bcc":{"type":"array","items":{"type":"string"}},"replyTo":{"type":"array","items":{"type":"string"}}},"required":["to","cc","bcc","replyTo"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate-schedule","never-runs","distant-next-run","skips-short-months","scheduled-email-stops","scheduled-delivery-without-schedule","no-recipients","template-shared","template-sends-pending","overwrites-datasheet-values","datasheets-keep-last-value"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["type","after","warnings"],"additionalProperties":false}]},"description":"What approving it changes, as the approval card in the app shows it: one entry per change, with the setting before and after it. `warnings` point out what the user should know before approving, such as a schedule that never runs."}},"required":["status","changes"],"additionalProperties":false},{"type":"object","properties":{"status":{"type":"string","enum":["awaiting_confirmation","cancelled","superseded","queued","sending","sent","partially_sent","failed","unconfirmed"],"description":"`awaiting_confirmation` while it waits for the user to decide, `cancelled` once rejected, and `superseded` when a later proposal in the chat replaced it. Once approved: `queued` and `sending` until every email is handed to the email provider, then `sent`, `partially_sent` or `failed`. `unconfirmed` when Rollstack lost track of the send, so some emails may have gone out."},"recipients":{"type":"array","items":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string"}},"cc":{"type":"array","items":{"type":"string"}},"bcc":{"type":"array","items":{"type":"string"}},"replyTo":{"type":"array","items":{"type":"string"}},"id":{"type":"string"},"label":{"type":"string"}},"required":["to","cc","bcc","replyTo","id","label"],"additionalProperties":false},"description":"Who receives the report: one email per group, each with its own addresses."},"sharingFormat":{"type":"string","enum":["pdf","ppt"],"description":"The file sent: the report's visible slides as a PDF (`pdf`) or PowerPoint file (`ppt`)."},"sendAttachmentAsLink":{"type":"boolean","description":"Whether the file is behind a download button in the email instead of attached."},"counts":{"anyOf":[{"type":"object","properties":{"total":{"type":"integer","minimum":0,"maximum":9007199254740991},"sent":{"type":"integer","minimum":0,"maximum":9007199254740991},"failed":{"type":"integer","minimum":0,"maximum":9007199254740991},"unknown":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["total","sent","failed","unknown"],"additionalProperties":false},{"type":"null"}],"description":"How many emails were handed to the email provider, failed, or ended unknown. `null` until the send starts."}},"required":["status","recipients","sharingFormat","sendAttachmentAsLink","counts"],"additionalProperties":false}]}},"required":["id","status","type","content"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/runs/{runId}":{"get":{"operationId":"getReportRun","summary":"Get report run","description":"A run's status and the datasheets, or visualizations on a report of another type than SlideDeck, it could not refresh. Waits up to waitSeconds for the run to end and answers as soon as it does, so call it again while the status is running. A user's later run of the report reuses the id, so this describes the latest one.\n\nRequires the `slide_decks:read` scope.","tags":["Runs"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`.","schema":{"type":"string","description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`."}},{"name":"runId","in":"path","required":true,"description":"The run, by the `runId` that `startReportRun` returned. Runs of a report started by the same member share one id, so it always refers to that member's latest run of the report.","schema":{"type":"string","description":"The run, by the `runId` that `startReportRun` returned. Runs of a report started by the same member share one id, so it always refers to that member's latest run of the report."}},{"name":"waitSeconds","in":"query","required":false,"description":"How long this call waits for the work to finish, in seconds: the message to the slides agent on `getReportMessage`, the run on `getReportRun`. It returns as soon as the work is done, or as things stand once the time is up, so call it again while `status` is still `queued` or `running`. `0` returns at once. Defaults to `20`; at most `30`.","schema":{"default":20,"description":"How long this call waits for the work to finish, in seconds: the message to the slides agent on `getReportMessage`, the run on `getReportRun`. It returns as soon as the work is done, or as things stand once the time is up, so call it again while `status` is still `queued` or `running`. `0` returns at once. Defaults to `20`; at most `30`.","type":"integer","minimum":0,"maximum":30}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"runId":{"type":"string","description":"Identifies the run, as returned by `startReportRun`."},"status":{"type":"string","enum":["running","completed","failed","cancelled","timed_out"],"description":"Where the run stands. It stays `running` until the run ends, then says how it ended.\n\n- `running`: the run is still updating the report. Call `getReportRun` again to keep waiting.\n- `completed`: the run finished. Datasheets, or visualizations on a report of another type than `SlideDeck`, it could not refresh, if any, keep their previous data and are listed in `errors`.\n- `failed`: nothing could be refreshed, or the run stopped on an error. `errors` lists the datasheets or visualizations it could not refresh.\n- `cancelled`: the run was stopped before it finished, for example with `cancelReportRun` or \"Cancel update\" in the app. Datasheets and visualizations it had already refreshed keep their new data.\n- `timed_out`: the run went past its time limit and was stopped."},"startedAt":{"description":"When the run started.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"finishedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the run ended, whatever its outcome. `null` while it is `running`."},"errors":{"type":"array","items":{"type":"object","properties":{"datasheetId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The datasheet that could not be refreshed, as `id` in `listReportDatasheets`. `null` on a report of another type than `SlideDeck`, whose runs refresh visualizations instead: `name` then names the visualization."},"name":{"type":"string","description":"The datasheet's or visualization's name, as shown in the app. The report's own name when a run of a report of another type than `SlideDeck` failed as a whole, with no visualization to blame."},"message":{"type":"string","description":"Why it could not be refreshed, for example an error reading its source or computing its data. Empty when no reason was recorded."}},"required":["datasheetId","name","message"],"additionalProperties":false},"description":"The datasheets, or visualizations on a report of another type than `SlideDeck`, the run could not refresh, each with the reason. While the run is `running`, those that have failed so far; on a `SlideDeck` report, once the run has `failed`, also those it had not finished. Empty when nothing failed. To run only these datasheets again, pass their ids as `datasheetIds` to `startReportRun`."}},"required":["runId","status","startedAt","finishedAt","errors"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/runs":{"post":{"operationId":"startReportRun","summary":"Start report run","description":"Refreshes a report's data, or only some of its datasheets, then repairs failed calculations and the slides with AI. On a report of another type than SlideDeck, such as a Google Slides presentation, refreshes every visualization instead, as Update in the app does, updating its file when it has one (an Email report has none), and emails the report when its email trigger is all. Answers the run's id at once; while a run of the report is already going, from the API, the app or its schedule, it answers that run's id with started false and starts nothing.\n\nRequires the `slide_decks:run` scope.","tags":["Runs"],"x-scope":"slide_decks:run","security":[{"apiKey":[]},{"oauth2":["slide_decks:run"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`.","schema":{"type":"string","description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`."}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","default":{},"type":"object","properties":{"datasheetIds":{"description":"The datasheets to update, from `listReportDatasheets`, instead of the whole report. Each must be a datasheet of this report. Unlike a run of the whole report, which reads every source again, a run of only some datasheets reuses the data last read from their sources: it reads a source again only if that data is missing or expired, or what the datasheet reads has changed, such as its source, its filters or the connection it reads with, as when you replace an uploaded file with `replaceDataset`. If omitted, the run updates the whole report. 1 to 500 ids. Only on reports whose `type` is `SlideDeck`: a report of another type has no datasheets and always runs whole, so passing it returns `400`.","minItems":1,"maxItems":500,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","examples":["d7b9a1c3-e5f7-4a9b-8c1d-3e5f7a9b1c2d"]}}},"additionalProperties":false}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"runId":{"type":"string","description":"Identifies the run. Pass it as `runId` to `getReportRun` to follow the run until it ends, or to `cancelReportRun` to stop it."},"started":{"type":"boolean","description":"Whether this request started a new run. `false` when a run of the report was already in progress, whoever started it: through the API, in the app or on one of its schedules. In that case nothing new starts, `datasheetIds` is ignored, and `runId` is that run's id. To run the report with your request, wait for that run to end with `getReportRun`, then call `startReportRun` again."}},"required":["runId","started"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/runs/{runId}/cancel":{"post":{"operationId":"cancelReportRun","summary":"Cancel report run","description":"Cancels a run of a report, whoever started it. Only its editors may. A run that already ended stays as it is.\n\nRequires the `slide_decks:run` scope.","tags":["Runs"],"x-scope":"slide_decks:run","security":[{"apiKey":[]},{"oauth2":["slide_decks:run"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`.","schema":{"type":"string","description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`."}},{"name":"runId","in":"path","required":true,"description":"The run, by the `runId` that `startReportRun` returned. Runs of a report started by the same member share one id, so it always refers to that member's latest run of the report.","schema":{"type":"string","description":"The run, by the `runId` that `startReportRun` returned. Runs of a report started by the same member share one id, so it always refers to that member's latest run of the report."}}],"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/exports":{"post":{"operationId":"exportReport","summary":"Export report","description":"Exports a report as PDF or PowerPoint and answers a download link valid for 15 minutes. At most 10 exports a minute per user.\n\nRequires the `slide_decks:read` scope.","tags":["Exports"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"format":{"type":"string","enum":["pdf","pptx"],"description":"The kind of file to create. `pdf` is a PDF of the report's visible slides; hidden slides are left out. `pptx` is a PowerPoint file in which hidden slides are included but stay hidden, speaker notes are kept, and charts are images rather than editable charts."},"slideIds":{"description":"The slides to export, from `getReportContent` or a reply's `changedSlideIds`. The file keeps the report's slide order whatever order you list them in. Ids that are not slides of the report are ignored, and so are hidden slides in a PDF. If omitted, the whole report is exported.","minItems":1,"type":"array","items":{"type":"string","examples":["f1e2d3c4-b5a6-4978-8a1b-2c3d4e5f6a7b"]}}},"required":["format"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"url":{"type":"string","description":"A link that downloads the exported file, named after the report. Anyone who has the link can download the file, without an API key, until `expiresAt`."},"expiresAt":{"description":"When `url` stops working, 15 minutes after the export. Export the report again to get a new link.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["url","expiresAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/content":{"get":{"operationId":"getReportContent","summary":"Get report content","description":"What a viewer sees on a report's visible slides: titles, text, and each chart's and table's values. On a long report, pass slideIds for only the slides you need, such as a reply's changedSlideIds.\n\nRequires the `slide_decks:read` scope.","tags":["Content"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}},{"name":"slideIds","in":"query","required":false,"description":"The slides to return, from a reply's `changedSlideIds` or an earlier `getReportContent` call. If omitted, every visible slide is returned. Hidden slides and ids that are not slides of the report are ignored. Up to 20 ids: repeat the parameter for each one, as in `?slideIds=a&slideIds=b`.","schema":{"description":"The slides to return, from a reply's `changedSlideIds` or an earlier `getReportContent` call. If omitted, every visible slide is returned. Hidden slides and ids that are not slides of the report are ignored. Up to 20 ids: repeat the parameter for each one, as in `?slideIds=a&slideIds=b`.","anyOf":[{"type":"string"},{"minItems":1,"maxItems":20,"type":"array","items":{"type":"string"}}],"examples":["f1e2d3c4-b5a6-4978-8a1b-2c3d4e5f6a7b"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"slides":{"type":"array","items":{"type":"object","properties":{"index":{"type":"number","description":"The slide's position in the report as viewers see it, counting only visible slides and starting at `0`. It stays the same when `slideIds` narrows the list."},"id":{"type":"string","description":"Identifies the slide. Pass it in `slideIds` to `getReportSlideImages` or `exportReport`, or to `sendReportMessage` to tell the slides agent which slides your message is about."},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The slide's title: the text in its title box. `null` when the slide has no title box, or the box is empty."},"texts":{"type":"array","items":{"type":"string"},"description":"The text of each text box and shape on the slide, title included. Text from the slide's master and layout is left out, and so are empty boxes."},"charts":{"type":"array","items":{"type":"object","properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The chart title shown on the slide. `null` when the chart has no title, and always for a table."},"type":{"type":"string","description":"What kind of chart it is: `bar`, `line` or `pie`. A chart that combines kinds, such as bars with a line, takes the kind of its first series, and a chart with no series is `chart`. Always `table` for a table."},"values":{"type":"object","properties":{"columns":{"type":"array","items":{"type":"string"},"description":"The column headers: for a chart, the names of the data columns it draws; for a table, the text of its first row."},"rows":{"type":"array","items":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"null"}]}},"description":"The data, one array per row, with its values in the order of `columns`. A chart's numbers are raw values, before the chart's number format is applied; a table's cells are text. At most 200 rows; `truncated` says whether there were more."},"truncated":{"type":"boolean","description":"Whether the chart or table has more than 200 rows, in which case `rows` contains only the first 200."}},"required":["columns","rows","truncated"],"additionalProperties":false,"description":"The data the chart or table shows, as `columns` and `rows`."}},"required":["title","type","values"],"additionalProperties":false},"description":"The charts on the slide, with the data each one shows."},"tables":{"type":"array","items":{"type":"object","properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The chart title shown on the slide. `null` when the chart has no title, and always for a table."},"type":{"type":"string","description":"What kind of chart it is: `bar`, `line` or `pie`. A chart that combines kinds, such as bars with a line, takes the kind of its first series, and a chart with no series is `chart`. Always `table` for a table."},"values":{"type":"object","properties":{"columns":{"type":"array","items":{"type":"string"},"description":"The column headers: for a chart, the names of the data columns it draws; for a table, the text of its first row."},"rows":{"type":"array","items":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"null"}]}},"description":"The data, one array per row, with its values in the order of `columns`. A chart's numbers are raw values, before the chart's number format is applied; a table's cells are text. At most 200 rows; `truncated` says whether there were more."},"truncated":{"type":"boolean","description":"Whether the chart or table has more than 200 rows, in which case `rows` contains only the first 200."}},"required":["columns","rows","truncated"],"additionalProperties":false,"description":"The data the chart or table shows, as `columns` and `rows`."}},"required":["title","type","values"],"additionalProperties":false},"description":"The tables on the slide, with the text of their cells. A table's first row is returned as its `columns`, and the other rows as its `rows`."}},"required":["index","id","title","texts","charts","tables"],"additionalProperties":false},"description":"The report's visible slides in report order, or only those in `slideIds`. Hidden slides are never included."}},"required":["slides"],"additionalProperties":false,"description":"What viewers see on the report's visible slides: each slide's title and text, and the data its charts and tables show. Data the slides do not show is never included."}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/slides/images":{"get":{"operationId":"getReportSlideImages","summary":"Get slide images","description":"Renders slides of a report as images, as viewers see them, so you can check how they look: text that overflows or overlaps, or a chart too small to read. After a message's turn, pass its replies' changedSlideIds. At most 10 slides a call; hidden slides are left out. Counts against the 10 exports a minute per user.\n\nRequires the `slide_decks:read` scope.","tags":["Content"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}},{"name":"slideIds","in":"query","required":true,"description":"The slides to render, from `getReportContent` or a reply's `changedSlideIds`. Hidden slides and ids that are not slides of the report are ignored. 1 to 10 ids: repeat the parameter for each one, as in `?slideIds=a&slideIds=b`.","schema":{"description":"The slides to render, from `getReportContent` or a reply's `changedSlideIds`. Hidden slides and ids that are not slides of the report are ignored. 1 to 10 ids: repeat the parameter for each one, as in `?slideIds=a&slideIds=b`.","anyOf":[{"type":"string"},{"minItems":1,"maxItems":10,"type":"array","items":{"type":"string"}}],"examples":["f1e2d3c4-b5a6-4978-8a1b-2c3d4e5f6a7b"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"slides":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The slide the image shows, as passed in `slideIds`."},"mimeType":{"type":"string","const":"image/jpeg","description":"The format of the image. Always `image/jpeg`."},"data":{"type":"string","format":"base64","contentEncoding":"base64","pattern":"^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$","description":"The slide as viewers see it, as a JPEG image encoded in base64."}},"required":["id","mimeType","data"],"additionalProperties":false},"description":"The rendered slides, in report order, whatever order `slideIds` lists them in. Hidden slides, and any slide that could not be rendered, are left out."}},"required":["slides"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/datasets":{"post":{"operationId":"createDataset","summary":"Upload a file","description":"Stores a CSV for the slides agent to build slides from: a header row, then at least one data row, at most 10 MB. Add it to a report with addReportDatasheets. Over MCP the CSV is written into the tool call, so send large files to this REST endpoint instead. Or send an Excel workbook (.xlsx, at most 10 MB) as multipart/form-data in the file field: it is stored as it is, with all its sheets, formatting and charts, and the user picks its sheets and ranges for a report in the app's editor. Legacy .xls, macro-enabled and password-protected workbooks are rejected. A workbook is read as saved: formulas show their saved results, and nothing is recalculated.\n\nRequires the `slide_decks:write` scope.","tags":["Uploaded files"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"description":"A name for the uploaded file, which its datasheet takes when you add the file to a report with `addReportDatasheets`. Leading and trailing spaces are removed, and a name containing a `/` keeps only its last part: `exports/Q3 pipeline` is stored as `Q3 pipeline`. From 1 to 255 characters.","examples":["Q3 pipeline"]},"csv":{"type":"string","minLength":1,"description":"The file's data, as CSV text: a header row naming the columns, then at least one row of data. With `replaceDataset`, it replaces the file's whole content, header included, and the uploaded file must be a CSV file. The header's names become the column names of the datasheets made from the file: a blank one becomes `Column N`, after the column's position, and a repeated one gets a `_2`, `_3` suffix. Values can be separated by commas, semicolons or tabs, detected from the header row. At most 10 MB.","examples":["region,revenue\nEMEA,1200000\nAmericas,2400000"]}},"required":["name","csv"],"additionalProperties":false}},"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"The Excel workbook to upload. With `createDataset`, it becomes a new uploaded file named after the file, such as `Q3 pipeline.xlsx`; with `replaceDataset`, it replaces the content of an uploaded workbook, which keeps its id and name. An uploaded workbook can't be added to a report with `addReportDatasheets`, which takes uploaded CSV files only. The file's name must end in `.xlsx`, and it can be at most 10 MB; legacy `.xls`, macro-enabled and password-protected workbooks are rejected."}},"required":["file"]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the uploaded file. Pass it as `id` to `replaceDataset` and `deleteDataset` and, for a CSV file, as `datasetId` to `addReportDatasheets` to add it to a report."},"name":{"type":"string","description":"The uploaded file's name: the `name` it was created with for a CSV file, or the workbook's file name for an Excel workbook, such as `Q3 pipeline.xlsx`. Replacing the file's content doesn't change it."},"createdAt":{"description":"When the file was uploaded. Replacing its content doesn't change it.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the file's content was last replaced with `replaceDataset`, or when it was uploaded if it has never been replaced.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","name","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/datasets/{id}":{"put":{"operationId":"replaceDataset","summary":"Replace an uploaded file","description":"Replaces an uploaded CSV file's rows, or a workbook's content with a new .xlsx sent as multipart/form-data in the file field. It keeps its id, and a CSV is never replaced by a workbook or the other way round. Reports built on it show the new content after their next run or message to the slides agent. An invalid file leaves the current one in place, and a sheet or range the new workbook no longer has fails its datasheets' reads. Only the user who created it may.\n\nRequires the `slide_decks:write` scope.","tags":["Uploaded files"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The uploaded file to replace or delete: the `id` returned by `createDataset`. Only the user who uploaded the file can replace or delete it; for anyone else, the request fails with a `404`, as if the file did not exist.","schema":{"type":"string","description":"The uploaded file to replace or delete: the `id` returned by `createDataset`. Only the user who uploaded the file can replace or delete it; for anyone else, the request fails with a `404`, as if the file did not exist."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"csv":{"type":"string","minLength":1,"description":"The file's data, as CSV text: a header row naming the columns, then at least one row of data. With `replaceDataset`, it replaces the file's whole content, header included, and the uploaded file must be a CSV file. The header's names become the column names of the datasheets made from the file: a blank one becomes `Column N`, after the column's position, and a repeated one gets a `_2`, `_3` suffix. Values can be separated by commas, semicolons or tabs, detected from the header row. At most 10 MB.","examples":["region,revenue\nEMEA,1200000\nAmericas,2400000"]}},"required":["csv"],"additionalProperties":false}},"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"The Excel workbook to upload. With `createDataset`, it becomes a new uploaded file named after the file, such as `Q3 pipeline.xlsx`; with `replaceDataset`, it replaces the content of an uploaded workbook, which keeps its id and name. An uploaded workbook can't be added to a report with `addReportDatasheets`, which takes uploaded CSV files only. The file's name must end in `.xlsx`, and it can be at most 10 MB; legacy `.xls`, macro-enabled and password-protected workbooks are rejected."}},"required":["file"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the uploaded file. Pass it as `id` to `replaceDataset` and `deleteDataset` and, for a CSV file, as `datasetId` to `addReportDatasheets` to add it to a report."},"name":{"type":"string","description":"The uploaded file's name: the `name` it was created with for a CSV file, or the workbook's file name for an Excel workbook, such as `Q3 pipeline.xlsx`. Replacing the file's content doesn't change it."},"createdAt":{"description":"When the file was uploaded. Replacing its content doesn't change it.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the file's content was last replaced with `replaceDataset`, or when it was uploaded if it has never been replaced.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","name","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteDataset","summary":"Delete an uploaded file","description":"Deletes an uploaded CSV file or workbook. Reports built on it keep what they last showed, and their datasheets fail on the next read. Only the user who created it may.\n\nRequires the `slide_decks:write` scope.","tags":["Uploaded files"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The uploaded file to replace or delete: the `id` returned by `createDataset`. Only the user who uploaded the file can replace or delete it; for anyone else, the request fails with a `404`, as if the file did not exist.","schema":{"type":"string","description":"The uploaded file to replace or delete: the `id` returned by `createDataset`. Only the user who uploaded the file can replace or delete it; for anyone else, the request fails with a `404`, as if the file did not exist."}}],"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/datasheets":{"get":{"operationId":"listReportDatasheets","summary":"List report datasheets","description":"The datasheets a report's charts and tables are built from, with their source and when each was last read.\n\nRequires the `slide_decks:read` scope.","tags":["Datasheets"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the datasheet. Pass it as `datasheetId` to `getReportDatasheetData` to read its table, in `datasheetIds` on `startReportRun` to update only some datasheets, or in `datasheetIds` on `sendReportMessage` for the slides agent to use it."},"name":{"type":"string","description":"The datasheet's name, as shown in the report's editor, where editors can rename it. A datasheet added with `addReportDatasheets` starts out named after its uploaded file, its dashboard or dashboard tab, or its range, such as `A1:F20`."},"sourceType":{"anyOf":[{"type":"string","enum":["GoogleSheet","GoogleExcel","MicrosoftExcel","Tableau","Salesforce","Metabase","PowerBI","Looker","RollstackVariable","Lightdash","Omni","Sigma","Snowflake","Databricks","CsvUpload","XlsxUpload","ManualTable","Dbt"]},{"type":"null"}],"description":"The kind of source the datasheet reads; when it reads several, the kind of the first.\n\n- `Looker`, `Tableau`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma`: data from that BI tool, such as a dashboard, a tab or one of its charts.\n- `Salesforce`: a Salesforce report.\n- `Snowflake`, `Databricks`: a query run on that warehouse connection.\n- `GoogleSheet`, `MicrosoftExcel`: a sheet or range of a Google Sheets or Excel file.\n- `CsvUpload`: a CSV file uploaded with `createDataset` or in the report's editor.\n- `XlsxUpload`: a sheet or range of an Excel workbook uploaded to Rollstack.\n- `ManualTable`: values typed into the report's editor, or the data of a chart imported from PowerPoint.\n\nDatasheets don't read `GoogleExcel`, `RollstackVariable` or `Dbt` sources, so expect none of them here. `null` when the datasheet reads no source, or Rollstack no longer has a record of its first source; deleting an uploaded file or a connection doesn't make it `null`."},"sourceName":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The name of what the datasheet reads, such as a dashboard tab, a range like `A1:F20`, or an uploaded file. When it reads several sources, the first one's. `null` in the same cases as `sourceType`."},"lastReadAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When Rollstack last read the datasheet's source successfully and stored a fresh copy of its data; for a datasheet that reads several sources, the latest such read of any of them. `null` until a read succeeds."},"lastBuiltAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the datasheet's data was last applied to the report's slides, updating the charts, tables and pictures drawn from it. `null` when its current data hasn't been applied to the slides yet, for example while nothing in the report uses the datasheet."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Why the datasheet's latest update failed, while reading its source or applying its data to the slides, as a human-readable message. The slides keep showing the datasheet's last good data until an update succeeds. `null` when the latest update worked."}},"required":["id","name","sourceType","sourceName","lastReadAt","lastBuiltAt","error"],"additionalProperties":false}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"addReportDatasheets","summary":"Add sources to report","description":"Adds sources to a report as datasheets, and answers their ids in the order of the sources. A source is a CSV file uploaded with createDataset, or a dashboard of a Looker, Metabase, Omni, Lightdash, Sigma, Tableau or Power BI connection: find it with searchDashboards, confirm it with the user, optionally check its tabs and charts with getDashboard, and add it by its connection, id and tabId from getDashboard's tabs, or from searchDashboards for a Sigma workbook found by a link (else the tab it opens on, a Power BI report's or Sigma workbook's first page). A dashboard comes in as one picture of the tab, read with the user's access to the connection, from which the slides agent can add its charts, except Tableau's and Power BI's, whose charts only the app lists. A source can also be a range of a Google Sheets or Excel file the user added in the app: find the file with searchSpreadsheets, take the sheet's id from getSpreadsheet, and pass the range inside the sheet in A1 notation, like A1:F20. A range comes in as a table, read with the user's own Google or Microsoft account on every run. Pass the ids as datasheetIds on sendReportMessage for the slides agent to build slides from them. Only the report's editors may.\n\nRequires the `slide_decks:write` scope.","tags":["Datasheets"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"sources":{"minItems":1,"maxItems":100,"type":"array","items":{"anyOf":[{"type":"object","properties":{"datasetId":{"type":"string","description":"The uploaded CSV file to add: the `id` returned by `createDataset`. The datasheet contains the whole CSV as one table and is named after the file. It can be any uploaded CSV file of the report's organization, including one another member uploaded; an uploaded workbook is rejected.","examples":["b2c4d6e8-f0a1-4b3c-9d5e-7f9a1b3c5d7e"]}},"required":["datasetId"],"additionalProperties":false},{"type":"object","properties":{"connectionType":{"type":"string","enum":["Looker","Metabase","Omni","Lightdash","Tableau","PowerBI","Sigma"],"description":"The type of the connection the dashboard is on: `Looker`, `Metabase`, `Omni`, `Lightdash`, `Sigma`, `Tableau` or `PowerBI`. It must match the connection's `type` in `listConnections`."},"connectionId":{"type":"string","description":"The connection the dashboard is on: the `id` of a connection from `listConnections`. You must have access to the connection in Rollstack.","examples":["c8e0a2b4-d6f8-4a0b-8c2d-4e6f8a0b2c4d"]},"dashboardId":{"type":"string","description":"The dashboard to add: the `id` of a dashboard from `searchDashboards` on this connection. For Tableau and Sigma, it is a workbook, and for Power BI, a report.","examples":["128"]},"tabId":{"description":"The tab to add: one of the `tabs[].id` values from `getDashboard`, which for Tableau are a workbook's views, for Power BI a report's pages and for Sigma a workbook's pages, or the `tabId` of a Sigma workbook `searchDashboards` found by a link. The datasheet is a picture of that tab, named after it. If omitted, Rollstack adds the tab the dashboard opens on (the first view or page for Tableau, Power BI and Sigma), or, for a dashboard without tabs such as an Omni dashboard, the whole dashboard, named after it. A tab the dashboard doesn't have is rejected.","examples":["12-overview"],"type":"string"}},"required":["connectionType","connectionId","dashboardId"],"additionalProperties":false},{"type":"object","properties":{"spreadsheetId":{"type":"string","description":"The Google Sheets or Excel file to read from: the `id` of a file from `searchSpreadsheets`. It must be a file you added in the app yourself.","examples":["e6f8a0b2-c4d6-4e8f-9a0b-2c4d6e8f0a1b"]},"sheetId":{"type":"string","description":"The sheet the range is on: one of the `sheets[].id` values from `getSpreadsheet`. A sheet the file doesn't have is rejected.","examples":["0"]},"range":{"type":"string","description":"The cells to read from the sheet, in A1 notation without the sheet's name, such as `A1:F20`, or `B2` for a single cell. The datasheet contains them as a table and is named after the range. Start the range at the header row so the columns take its names; without a header, they are named `Column 1`, `Column 2` and so on. Hidden rows and columns are left out, and whole columns such as `A:F` aren't accepted.","examples":["A1:F20"]}},"required":["spreadsheetId","sheetId","range"],"additionalProperties":false}]},"description":"The data to add to the report, each source becoming one of its datasheets: an uploaded CSV file (`datasetId`), a dashboard tab (`connectionType`, `connectionId`, `dashboardId` and optionally `tabId`), or a range of a spreadsheet (`spreadsheetId`, `sheetId` and `range`). An uploaded file or a range comes in as a table, and a dashboard tab as a picture of the tab. If any source can't be added, none is. From 1 to 100 sources."}},"required":["sources"],"additionalProperties":false}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"datasheetIds":{"type":"array","items":{"type":"string"},"description":"Unique identifiers of the new datasheets, one per source, in the same order as `sources`. Pass them as `datasheetIds` on `sendReportMessage` for the slides agent to build slides from them."}},"required":["datasheetIds"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/datasheets/{datasheetId}/data":{"get":{"operationId":"getReportDatasheetData","summary":"Get datasheet data","description":"The table a report's chart is drawn from: the datasheet's steps run over the copies stored at its sources' last reads; the source is never queried. Only the report's editors may: the table was read with an editor's credentials, can hold columns and rows the slides never show, and skips the source's row-level security. Fails until every source it reads has been read, after a source's latest read failed, and once a stored copy expires, 30 days after its read. At most 30 reads a minute per user.\n\nRequires the `slide_decks:read` scope.","tags":["Datasheets"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}},{"name":"datasheetId","in":"path","required":true,"description":"The datasheet whose table to read: an `id` from `listReportDatasheets`, or one of the `datasheetIds` returned by `addReportDatasheets`. It must be one of this report's datasheets. A datasheet that reads a picture, such as a dashboard tab added with `addReportDatasheets`, has no table, so the request fails.","schema":{"type":"string","description":"The datasheet whose table to read: an `id` from `listReportDatasheets`, or one of the `datasheetIds` returned by `addReportDatasheets`. It must be one of this report's datasheets. A datasheet that reads a picture, such as a dashboard tab added with `addReportDatasheets`, has no table, so the request fails."}},{"name":"limit","in":"query","required":false,"description":"The maximum number of rows to return, starting from the first row of the table. If the table has more, `truncated` is `true`. Can range from `1` to `1000`. Defaults to `200`.","schema":{"default":200,"description":"The maximum number of rows to return, starting from the first row of the table. If the table has more, `truncated` is `true`. Can range from `1` to `1000`. Defaults to `200`.","type":"integer","minimum":1,"maximum":1000}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"columns":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"The column's name in the datasheet's table, which the report's charts and tables use to refer to it. Unless the datasheet renames it, a column read from an uploaded file or a spreadsheet range is named after its header; a blank header becomes `Column N`, after the column's position, and a repeated one gets a `_2`, `_3` suffix."},"label":{"description":"The column's display name, when its source gives one, such as a field's label in Looker or Metabase. Charts and tables drawn from the datasheet show it instead of `name`, unless a table renames the column. Omitted when the column has none.","type":"string"},"type":{"type":"string","enum":["number","date","string","boolean"],"description":"What the column's cells contain: `number` for numbers, `date` for dates and times, `string` for text, and `boolean` for `true` or `false`. Any cell can also be `null` when it is empty."}},"required":["name","type"],"additionalProperties":false},"description":"The columns of the table, in the same order as the cells of each row in `rows`."},"rows":{"type":"array","items":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"}]}},"description":"The rows of the table, starting from the first, at most `limit` of them. Each row is an array of cells in the order of `columns`. An empty cell is `null`, and a `date` cell is an ISO 8601 string in UTC, at midnight when the source gives a day without a time."},"stacking":{"description":"How the chart in the datasheet's source stacks its series, such as a Looker, Metabase or Power BI chart, or a chart imported from PowerPoint. Area, bar and column charts drawn from the datasheet stack the same way, unless their own Stacking setting overrides it. `none` doesn't stack the series, `stacked` piles them on top of one another, and `percent` piles them up to 100% so each shows its share of the total. Omitted when the source sets no stacking, as with an uploaded file or a spreadsheet range; charts then don't stack unless set to.","type":"string","enum":["none","stacked","percent"]},"totalRow":{"type":"boolean","const":true},"truncated":{"type":"boolean","description":"Whether the table has more rows than `limit`, so `rows` doesn't contain all of them. Raise `limit` to get more, up to the first `1000` rows."},"readAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"When Rollstack read the source data the table is built from. For a datasheet that reads several sources, the oldest of those reads."}},"required":["columns","rows","truncated","readAt"],"additionalProperties":false,"description":"The datasheet's table: the data Rollstack stored at its sources' latest reads, after the datasheet's own transformations, such as filters, joins, pivots or SQL. The report's charts and tables draw from it, and it can contain columns and rows the slides don't show."}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/parameters":{"get":{"operationId":"getReportParameters","summary":"Get report parameters","description":"A report's parameters, with which ones a burst can vary by, and the dashboard filters a parameter can link, with the parameter that already links each.\n\nRequires the `slide_decks:read` scope.","tags":["Parameters"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"parameters":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The report parameter's id. Pass it in `parameterIds` to `createBurst` when `burstable` is `true`."},"name":{"type":"string","description":"The report parameter's name, as shown in Rollstack."},"value":{"anyOf":[{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"categorical"},"values":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"operator":{"type":"string","enum":["is","is_not","contains","doesnt_contain"]}},"required":["type","values"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_range"},"startDate":{"type":"string"},"endDate":{"type":"string"}},"required":["type","subtype","startDate","endDate"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_relative"},"rangeType":{"type":"string","enum":["current","lastN","nextN"]},"rangeN":{"type":"number"},"periodType":{"type":"string","enum":["days","weeks","months","quarters","years","completeDays","completeWeeks","completeMonths","completeQuarters","completeYears"]}},"required":["type","subtype","rangeType","rangeN","periodType"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_month_year"},"month":{"type":"number"},"year":{"type":"number"}},"required":["type","subtype","month","year"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_quarter_year"},"quarter":{"type":"number"},"year":{"type":"number"}},"required":["type","subtype","quarter","year"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_single"},"date":{"type":"string"}},"required":["type","subtype","date"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_null"}},"required":["type","subtype"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"number"},"value":{"type":"number"}},"required":["type","value"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"text"},"value":{"type":"string","minLength":1}},"required":["type","value"],"additionalProperties":false}]},{"type":"null"}],"description":"The parameter's value, which the report's datasheets read through the filters it links. `null` when it has none, and those filters keep their own values. A value of a report parameter, in the shape of its type. Copy the shape of the parameter's `value` in `listBursts`, or of a variant's in `listBurstVariants`:\n\n- A list of values: `{ \"type\": \"categorical\", \"values\": [\"EMEA\"] }`, with at least one value. `operator` can also be `is_not`, `contains` or `doesnt_contain`; it is `is` when left out.\n- A number: `{ \"type\": \"number\", \"value\": 10 }`. Text: `{ \"type\": \"text\", \"value\": \"EMEA\" }`.\n- A date range: `{ \"type\": \"date\", \"subtype\": \"date_range\", \"startDate\": \"2026-01-01\", \"endDate\": \"2026-03-31\" }`. One date: `{ \"type\": \"date\", \"subtype\": \"date_single\", \"date\": \"2026-03-31\" }`.\n- A month or a quarter: `{ \"type\": \"date\", \"subtype\": \"date_month_year\", \"month\": 3, \"year\": 2026 }` (months 1 to 12), `{ \"type\": \"date\", \"subtype\": \"date_quarter_year\", \"quarter\": 1, \"year\": 2026 }`.\n- A relative period: `{ \"type\": \"date\", \"subtype\": \"date_relative\", \"rangeType\": \"lastN\", \"rangeN\": 3, \"periodType\": \"months\" }`. `rangeType` is `current`, `lastN` or `nextN`; `periodType` is `days`, `weeks`, `months`, `quarters` or `years`, or `completeDays` through `completeYears` for whole periods only."},"burstable":{"type":"boolean","description":"Whether a burst can vary by the parameter: it links at least one filter whose `valueType` isn't `null`. A parameter that links no such filter can't be."}},"required":["id","name","value","burstable"],"additionalProperties":false},"description":"The report's parameters, oldest first. Empty until one is created, here or in the app."},"filters":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The filter's id. Pass it in `filterIds` to `createReportParameter`."},"name":{"type":"string","description":"The filter's name on its dashboard."},"connectionType":{"type":"string","enum":["GoogleSheet","GoogleExcel","MicrosoftExcel","Tableau","Salesforce","Metabase","PowerBI","Looker","RollstackVariable","Lightdash","Omni","Sigma","Snowflake","Databricks","CsvUpload","XlsxUpload","ManualTable","Dbt"],"description":"The kind of connection the dashboard is on, such as `Looker`."},"dashboardName":{"type":"string","description":"The dashboard the filter is on, as its connection names it."},"datasheets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The datasheet's id, as in `listReportDatasheets`."},"name":{"type":"string","description":"The datasheet's name."}},"required":["id","name"],"additionalProperties":false},"description":"The report's datasheets that read the filter's dashboard, which a parameter linking it writes its value into."},"parameterId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The parameter that links the filter, by its `id` in `parameters`. A filter follows one parameter at most, so a new parameter can only link filters where this is `null`."},"valueType":{"anyOf":[{"type":"string","enum":["categorical","date","number","text"]},{"type":"null"}],"description":"The kind of value Rollstack can set in the filter, and so the `type` of a parameter value that reaches it. `null` when only the dashboard's own embed can edit the filter: a parameter can link it, but can't set its value or be burst by it."}},"required":["id","name","connectionType","dashboardName","datasheets","parameterId","valueType"],"additionalProperties":false},"description":"The filters a parameter can link: those of the dashboards the report's datasheets read. Empty when the report reads no dashboard, such as one built only from uploaded files and spreadsheet ranges, which can't have parameters."}},"required":["parameters","filters"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createReportParameter","summary":"Create report parameter","description":"Creates a parameter of a report, linked to the dashboard filters given, as the app's report parameters editor does. With a value, writes it into those filters and reads their datasheets again. Answers the parameter. Only the report's editors may.\n\nRequires the `slide_decks:write` scope.","tags":["Parameters"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"type":"string","minLength":1,"description":"The parameter's name, as shown in Rollstack. It can't be the name of another parameter of the report.","examples":["Region"]},"filterIds":{"maxItems":200,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"description":"The filters the parameter links, by their `id` in `filters` from `getReportParameters`: its value is written into each, in every datasheet that reads its dashboard. Each must have no `parameterId` yet. A burst can vary by the parameter only if one of them has a `valueType`."},"value":{"default":null,"description":"The parameter's value, of the `valueType` of the filters it links. When set, it is written into those filters and their datasheets are read again with it, so the report's slides change. If `null` or omitted, as for a parameter a burst's variants will set, the filters keep their own values. A value of a report parameter, in the shape of its type. Copy the shape of the parameter's `value` in `listBursts`, or of a variant's in `listBurstVariants`:\n\n- A list of values: `{ \"type\": \"categorical\", \"values\": [\"EMEA\"] }`, with at least one value. `operator` can also be `is_not`, `contains` or `doesnt_contain`; it is `is` when left out.\n- A number: `{ \"type\": \"number\", \"value\": 10 }`. Text: `{ \"type\": \"text\", \"value\": \"EMEA\" }`.\n- A date range: `{ \"type\": \"date\", \"subtype\": \"date_range\", \"startDate\": \"2026-01-01\", \"endDate\": \"2026-03-31\" }`. One date: `{ \"type\": \"date\", \"subtype\": \"date_single\", \"date\": \"2026-03-31\" }`.\n- A month or a quarter: `{ \"type\": \"date\", \"subtype\": \"date_month_year\", \"month\": 3, \"year\": 2026 }` (months 1 to 12), `{ \"type\": \"date\", \"subtype\": \"date_quarter_year\", \"quarter\": 1, \"year\": 2026 }`.\n- A relative period: `{ \"type\": \"date\", \"subtype\": \"date_relative\", \"rangeType\": \"lastN\", \"rangeN\": 3, \"periodType\": \"months\" }`. `rangeType` is `current`, `lastN` or `nextN`; `periodType` is `days`, `weeks`, `months`, `quarters` or `years`, or `completeDays` through `completeYears` for whole periods only.","anyOf":[{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"categorical"},"values":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"operator":{"type":"string","enum":["is","is_not","contains","doesnt_contain"]}},"required":["type","values"]},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_range"},"startDate":{"type":"string"},"endDate":{"type":"string"}},"required":["type","subtype","startDate","endDate"]},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_relative"},"rangeType":{"type":"string","enum":["current","lastN","nextN"]},"rangeN":{"type":"number"},"periodType":{"type":"string","enum":["days","weeks","months","quarters","years","completeDays","completeWeeks","completeMonths","completeQuarters","completeYears"]}},"required":["type","subtype","rangeType","rangeN","periodType"]},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_month_year"},"month":{"type":"number"},"year":{"type":"number"}},"required":["type","subtype","month","year"]},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_quarter_year"},"quarter":{"type":"number"},"year":{"type":"number"}},"required":["type","subtype","quarter","year"]},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_single"},"date":{"type":"string"}},"required":["type","subtype","date"]},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_null"}},"required":["type","subtype"]},{"type":"object","properties":{"type":{"type":"string","const":"number"},"value":{"type":"number"}},"required":["type","value"]},{"type":"object","properties":{"type":{"type":"string","const":"text"},"value":{"type":"string","minLength":1}},"required":["type","value"]}]},{"type":"null"}]}},"required":["name","filterIds"],"additionalProperties":false}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"The report parameter's id. Pass it in `parameterIds` to `createBurst` when `burstable` is `true`."},"name":{"type":"string","description":"The report parameter's name, as shown in Rollstack."},"value":{"anyOf":[{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"categorical"},"values":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"operator":{"type":"string","enum":["is","is_not","contains","doesnt_contain"]}},"required":["type","values"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_range"},"startDate":{"type":"string"},"endDate":{"type":"string"}},"required":["type","subtype","startDate","endDate"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_relative"},"rangeType":{"type":"string","enum":["current","lastN","nextN"]},"rangeN":{"type":"number"},"periodType":{"type":"string","enum":["days","weeks","months","quarters","years","completeDays","completeWeeks","completeMonths","completeQuarters","completeYears"]}},"required":["type","subtype","rangeType","rangeN","periodType"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_month_year"},"month":{"type":"number"},"year":{"type":"number"}},"required":["type","subtype","month","year"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_quarter_year"},"quarter":{"type":"number"},"year":{"type":"number"}},"required":["type","subtype","quarter","year"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_single"},"date":{"type":"string"}},"required":["type","subtype","date"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_null"}},"required":["type","subtype"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"number"},"value":{"type":"number"}},"required":["type","value"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"text"},"value":{"type":"string","minLength":1}},"required":["type","value"],"additionalProperties":false}]},{"type":"null"}],"description":"The parameter's value, which the report's datasheets read through the filters it links. `null` when it has none, and those filters keep their own values. A value of a report parameter, in the shape of its type. Copy the shape of the parameter's `value` in `listBursts`, or of a variant's in `listBurstVariants`:\n\n- A list of values: `{ \"type\": \"categorical\", \"values\": [\"EMEA\"] }`, with at least one value. `operator` can also be `is_not`, `contains` or `doesnt_contain`; it is `is` when left out.\n- A number: `{ \"type\": \"number\", \"value\": 10 }`. Text: `{ \"type\": \"text\", \"value\": \"EMEA\" }`.\n- A date range: `{ \"type\": \"date\", \"subtype\": \"date_range\", \"startDate\": \"2026-01-01\", \"endDate\": \"2026-03-31\" }`. One date: `{ \"type\": \"date\", \"subtype\": \"date_single\", \"date\": \"2026-03-31\" }`.\n- A month or a quarter: `{ \"type\": \"date\", \"subtype\": \"date_month_year\", \"month\": 3, \"year\": 2026 }` (months 1 to 12), `{ \"type\": \"date\", \"subtype\": \"date_quarter_year\", \"quarter\": 1, \"year\": 2026 }`.\n- A relative period: `{ \"type\": \"date\", \"subtype\": \"date_relative\", \"rangeType\": \"lastN\", \"rangeN\": 3, \"periodType\": \"months\" }`. `rangeType` is `current`, `lastN` or `nextN`; `periodType` is `days`, `weeks`, `months`, `quarters` or `years`, or `completeDays` through `completeYears` for whole periods only."},"burstable":{"type":"boolean","description":"Whether a burst can vary by the parameter: it links at least one filter whose `valueType` isn't `null`. A parameter that links no such filter can't be."},"runId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The run that reads again the datasheets the value was written into, as `runId` in `getReportRun`. When a run of the report is already going, it reads them after that run. `null` when no value was written, or when you can't run the report."}},"required":["id","name","value","burstable","runId"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/shares/{userId}":{"put":{"operationId":"shareReport","summary":"Share report","description":"Shares a report of any type with a member of the organization to view or edit it, or changes their permission. They get an email. A report that updates a file, such as a Google Slides presentation, also shares the file with them, as the app does.\n\nRequires the `slide_decks:write` scope.","tags":["Sharing"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`.","schema":{"type":"string","description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`."}},{"name":"userId","in":"path","required":true,"description":"The member to share the report with, or to unshare it from. Use their `id` from `listMembers`, which only owners and admins can call, or their `userId` in `sharedWith` from `getReport` if the report is already shared with them. You can share a report only with active members of the organization, and not with yourself. Anyone the report is shared with can unshare it from themselves, even with `view` permission.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The member to share the report with, or to unshare it from. Use their `id` from `listMembers`, which only owners and admins can call, or their `userId` in `sharedWith` from `getReport` if the report is already shared with them. You can share a report only with active members of the organization, and not with yourself. Anyone the report is shared with can unshare it from themselves, even with `view` permission."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"permission":{"type":"string","enum":["view","comment","edit"],"description":"What the member can do with the report. `view` lets them open, export and duplicate it. `comment` also lets them add, reply to and resolve comments on its slides. `edit` also lets them change its slides, data, schedules, email and other settings, run it, send its email, chat with the slides agent about it, and manage who it's shared with. Neither lets them delete the report or transfer its ownership. If the report is already shared with the member, this replaces their permission and they aren't notified again. On a report that updates a file in Google Drive or OneDrive, Rollstack also shares the file with them, as the app does."}},"required":["permission"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"userId":{"type":"number","description":"The member the report is now shared with: the `userId` from the path."},"permission":{"type":"string","enum":["view","comment","edit"],"description":"What the member can now do with the report: the `permission` you sent."}},"required":["userId","permission"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"unshareReport","summary":"Unshare report","description":"Removes a user's share of a report of any type, and their access to its file when it updates one, as the app does.\n\nRequires the `slide_decks:write` scope.","tags":["Sharing"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`.","schema":{"type":"string","description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`."}},{"name":"userId","in":"path","required":true,"description":"The member to share the report with, or to unshare it from. Use their `id` from `listMembers`, which only owners and admins can call, or their `userId` in `sharedWith` from `getReport` if the report is already shared with them. You can share a report only with active members of the organization, and not with yourself. Anyone the report is shared with can unshare it from themselves, even with `view` permission.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The member to share the report with, or to unshare it from. Use their `id` from `listMembers`, which only owners and admins can call, or their `userId` in `sharedWith` from `getReport` if the report is already shared with them. You can share a report only with active members of the organization, and not with yourself. Anyone the report is shared with can unshare it from themselves, even with `view` permission."}}],"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/schedules":{"get":{"operationId":"getReportSchedules","summary":"List schedules","description":"The schedules of a report of any type, with when each runs next, or null for one that never runs again.\n\nRequires the `slide_decks:read` scope.","tags":["Schedules"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`.","schema":{"type":"string","description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`."}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the schedule. `updateReportSchedules` replaces every schedule, so the ids change each time you call it."},"frequency":{"type":"string","enum":["daily","weekly","monthly","quarterly","hourly","yearly"],"description":"How often the schedule runs. `hourly` runs every day at each time in `selectedTimes`. `daily`, `weekly`, `monthly` and `quarterly` run whenever `cronExpression` fires; those made in the app run every day, on chosen weekdays, on chosen days of the month, or every three months, respectively. `yearly` can't be set through the API or the app, and also runs on `cronExpression`."},"cronExpression":{"type":"string","description":"When the schedule runs, as a five-field cron expression (minute, hour, day of month, month, day of week) in the schedule's `timezone`. For an `hourly` schedule, Rollstack generates it from `selectedTimes` and runs the report at those times instead. Monthly schedules made in the app can use `L` and `#`, such as `0 9 L * *` (last day of the month) or `0 9 ? * 1#1` (first Monday)."},"selectedTimes":{"type":"array","items":{"type":"string"},"description":"The times of day an `hourly` schedule runs, every day, as 24-hour `HH:mm` in the schedule's `timezone`. Other frequencies don't use it; it's empty on those set through the API."},"startDate":{"description":"When the schedule starts: it never runs the report before this date and time. This is a local date and time in the schedule's `timezone`, written as if it were UTC: `2026-11-02T09:00:00Z` means 9:00 on November 2, 2026 in that timezone, not 9:00 UTC.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"endDate":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the schedule ends: it never runs the report after this date and time. `null` if the schedule never ends. Like `startDate`, this is a local date and time in the schedule's `timezone`, written as if it were UTC."},"timezone":{"type":"string","description":"The timezone the schedule runs in. Its run times (`cronExpression` or `selectedTimes`), `startDate` and `endDate` are all local times in this timezone, so a schedule set for 9:00 keeps running at 9:00 local time when daylight saving time starts or ends. Given as an IANA timezone name, such as `America/New_York`."},"nextRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the schedule will next run the report. `null` if it has no runs left before its `endDate`. Unlike `startDate` and `endDate`, this is an actual UTC time."}},"required":["id","frequency","cronExpression","selectedTimes","startDate","endDate","timezone","nextRunAt"],"additionalProperties":false}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"updateReportSchedules","summary":"Replace report schedules","description":"Replaces the schedules of a report of any type, at most 10; an empty list removes them all. Only its editors may. Every scheduled run updates the whole report: an AI update on a SlideDeck report, and a refresh of every visualization on a report that updates a file. Schedules are checked every 15 minutes, so a cron that fires more often still runs at most once per 15 minutes.\n\nRequires the `slide_decks:write` scope.","tags":["Schedules"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`.","schema":{"type":"string","description":"The report to act on, of any `type`, by its `id` from `listReports` or `createReport`. You can also copy it from the report's link in Rollstack (`appUrl`): it's the part right after `/slides/` or `/destinations/`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"schedules":{"maxItems":10,"type":"array","items":{"type":"object","properties":{"frequency":{"type":"string","enum":["hourly","daily","weekly","monthly","quarterly"],"description":"How often the schedule runs. `hourly` runs every day at each time in `selectedTimes`, and takes no `cronExpression`. `daily`, `weekly`, `monthly` and `quarterly` run whenever `cronExpression` fires, and take no `selectedTimes`. For those, the frequency doesn't change when the report runs, but the app uses it to describe and edit the schedule, so pick the one that matches your cron expression."},"cronExpression":{"description":"When a `daily`, `weekly`, `monthly` or `quarterly` schedule runs: a five-field cron expression (minute, hour, day of month, month, day of week) in the schedule's `timezone`, such as `0 9 * * 1` for every Monday at 9:00, or `0 9 L * *` for 9:00 on the last day of each month. Required for those frequencies; omit it for `hourly`. Rollstack checks schedules every 15 minutes, so the minute field must include 0, 15, 30 or 45, and runs at other minutes are skipped. At most 100 characters.","examples":["0 9 * * 1"],"type":"string","maxLength":100},"selectedTimes":{"description":"The times of day an `hourly` schedule runs, every day, as 24-hour `HH:mm` in the schedule's `timezone`, such as `09:00` or `13:45`. Required for `hourly`; omit it for other frequencies. Each time must be on the quarter hour (`:00`, `:15`, `:30` or `:45`). From 1 to 96 times.","minItems":1,"maxItems":96,"type":"array","items":{"type":"string","pattern":"^([01]\\d|2[0-3]):(00|15|30|45)$","examples":["09:00"]}},"startDate":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"When the schedule starts: it never runs the report before this date and time. This is a local date and time in the schedule's `timezone`, written as if it were UTC: `2026-11-02T09:00:00Z` means 9:00 on November 2, 2026 in that timezone, not 9:00 UTC. For frequencies other than `hourly`, set it to the date and time of the first run: the app shows its time as the schedule's time, and when someone changes the schedule's frequency or days there, it rebuilds `cronExpression` at that time.","examples":["2026-11-02T09:00:00Z"]},"endDate":{"default":null,"description":"When the schedule ends: it never runs the report after this date and time. Omit it or pass `null` for a schedule that never ends. Like `startDate`, this is a local date and time in the schedule's `timezone`, written as if it were UTC. Must be later than `startDate`. Set it later than the last run you want: a run at exactly this time may be skipped.","examples":["2027-11-02T09:00:00Z"],"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"timezone":{"type":"string","minLength":1,"description":"The timezone the schedule runs in. Its run times (`cronExpression` or `selectedTimes`), `startDate` and `endDate` are all local times in this timezone, so a schedule set for 9:00 keeps running at 9:00 local time when daylight saving time starts or ends. Given as an IANA timezone name, such as `America/New_York`. UTC offsets such as `+05:30` aren't accepted.","examples":["America/New_York"]}},"required":["frequency","startDate","timezone"],"additionalProperties":false},"description":"The report's new schedules. They replace all of its current schedules, so include any you want to keep; send an empty list to remove them all. When several schedules fall at the same time, the report runs once. Each one runs the whole report, even where a schedule set in the app ran only some visualizations of a report that updates a file. Up to 10."}},"required":["schedules"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the schedule. `updateReportSchedules` replaces every schedule, so the ids change each time you call it."},"frequency":{"type":"string","enum":["daily","weekly","monthly","quarterly","hourly","yearly"],"description":"How often the schedule runs. `hourly` runs every day at each time in `selectedTimes`. `daily`, `weekly`, `monthly` and `quarterly` run whenever `cronExpression` fires; those made in the app run every day, on chosen weekdays, on chosen days of the month, or every three months, respectively. `yearly` can't be set through the API or the app, and also runs on `cronExpression`."},"cronExpression":{"type":"string","description":"When the schedule runs, as a five-field cron expression (minute, hour, day of month, month, day of week) in the schedule's `timezone`. For an `hourly` schedule, Rollstack generates it from `selectedTimes` and runs the report at those times instead. Monthly schedules made in the app can use `L` and `#`, such as `0 9 L * *` (last day of the month) or `0 9 ? * 1#1` (first Monday)."},"selectedTimes":{"type":"array","items":{"type":"string"},"description":"The times of day an `hourly` schedule runs, every day, as 24-hour `HH:mm` in the schedule's `timezone`. Other frequencies don't use it; it's empty on those set through the API."},"startDate":{"description":"When the schedule starts: it never runs the report before this date and time. This is a local date and time in the schedule's `timezone`, written as if it were UTC: `2026-11-02T09:00:00Z` means 9:00 on November 2, 2026 in that timezone, not 9:00 UTC.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"endDate":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the schedule ends: it never runs the report after this date and time. `null` if the schedule never ends. Like `startDate`, this is a local date and time in the schedule's `timezone`, written as if it were UTC."},"timezone":{"type":"string","description":"The timezone the schedule runs in. Its run times (`cronExpression` or `selectedTimes`), `startDate` and `endDate` are all local times in this timezone, so a schedule set for 9:00 keeps running at 9:00 local time when daylight saving time starts or ends. Given as an IANA timezone name, such as `America/New_York`."},"nextRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the schedule will next run the report. `null` if it has no runs left before its `endDate`. Unlike `startDate` and `endDate`, this is an actual UTC time."}},"required":["id","frequency","cronExpression","selectedTimes","startDate","endDate","timezone","nextRunAt"],"additionalProperties":false}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/email-config":{"get":{"operationId":"getReportEmailConfig","summary":"Get email settings","description":"Who a report's email goes to and how it is sent. Answers 404 until its email is set up.\n\nRequires the `slide_decks:read` scope.","tags":["Email"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"to":{"type":"array","items":{"type":"string"},"description":"The addresses the report's email is sent to. When empty, no one receives it: the report's runs send no email and `sendReportEmail` returns 400."},"cc":{"type":"array","items":{"type":"string"},"description":"The addresses copied on the report's email, which every recipient can see."},"bcc":{"type":"array","items":{"type":"string"},"description":"The addresses that also receive the report's email without the other recipients seeing them."},"replyTo":{"type":"array","items":{"type":"string"},"description":"The addresses recipients' replies go to instead of the sender. They don't receive the email themselves. Empty when replies go to the sender."},"groupRecipients":{"type":"boolean","description":"Whether all the addresses in `to` receive one email together. When `false`, each address in `to` gets its own email with the same `cc`, `bcc` and `replyTo`, so the addresses in `cc` and `bcc` receive one copy per address in `to`."},"smtpServerId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The SMTP connection the report's email is sent through, from `listSmtpConnections`; recipients see its `from` address as the sender. `null` when the email is sent from Rollstack's own address."},"sharingFormat":{"type":"string","enum":["link","pdf","ppt","cloudLink"],"description":"How the email delivers the report. `pdf` and `ppt` send its slides, without the hidden ones, as a PDF or PowerPoint file, attached or behind a download button (see `sendAttachmentAsLink`). `cloudLink` (Exported link in the app) sends a link to the copy of the report exported to Google Drive or OneDrive, and shares that copy with the addresses in `to`, `cc` and `bcc` with the sharing permission set in the app, viewer unless changed there. If no permission is set, as after PDF or PPT was picked in the app, the copy isn't shared with them. `link` isn't available for reports: a report whose settings still contain it is emailed as a PDF behind a download button."},"sendAttachmentAsLink":{"type":"boolean","description":"Whether the email puts the `pdf` or `ppt` file behind a Download PDF or Download PPT button instead of attaching it. When `false`, the file is attached. Has no effect with `cloudLink`."},"trigger":{"type":"string","enum":["all","none","scheduled"],"description":"Which of the report's runs email it automatically. `all` and `scheduled` work the same way for reports: each run started by one of the report's schedules (see `getReportSchedules`) sends the email when it updates every datasheet, or when it updates some and all its failures are in `ignoredFailureStatusMessages`. A report with no datasheets is never emailed by its runs. With `none` (Manual in the app), no run sends it: the email goes out only when sent with `sendReportEmail` or from the app. Runs started any other way, such as with `startReportRun` or from the app, never send it."},"ignoredFailureStatusMessages":{"type":"array","items":{"type":"string","enum":["tableau_view_not_found","dashboard_not_found","dashboard_tab_not_found","dashboard_not_ready","dashboard_has_errors","dashboard_invalid_layout","metabase_element_not_found","looker_element_not_found","element_not_found","google_slide_not_found","slide_not_found","file_not_found","sheet_not_found","sheet_hidden","range_not_found","duplicate_file_failed","merged_range_on_filter_range","insufficient_permissions","image_cropping_failed","visualization_not_found","visualization_not_ready","visualization_has_errors","visualization_empty","invalid_credentials","missing_credentials","instance_unavailable","column_not_found","empty_data","fetch_summary_data_error","fetch_visual_specification_error","incorrect_data_structure","missing_data","missing_formatted_value","malformed_data","viz_not_ready","worksheet_not_found","sync_not_found","file_update_failed","internal_server_error"]},"description":"The failures that don't stop a scheduled run from emailing the report (see `trigger`). A run in which some datasheets fail still sends the email when all its failures are in this list; a run in which every datasheet fails never does. A report's run records each failed datasheet as `internal_server_error`, so that is the only value with an effect: when it is listed, a run in which only some datasheets fail sends the email.\n\nThe other values describe failures of visualizations taken from a BI dashboard, spreadsheet or data source, which a report's run never reports, so they have no effect:\n\n- `dashboard_not_found`, or the older `tableau_view_not_found`: the dashboard, Tableau workbook, Power BI report or spreadsheet could not be found.\n- `dashboard_tab_not_found`: the dashboard tab, Tableau view, Power BI report page or spreadsheet sheet could not be found.\n- `dashboard_not_ready`: the dashboard took too long to load.\n- `dashboard_has_errors`: the dashboard or spreadsheet failed to load because of an error in the tool it comes from.\n- `dashboard_invalid_layout`: the dashboard's layout is invalid, and it needs to be saved again.\n- `element_not_found`, or the older `metabase_element_not_found` and `looker_element_not_found`: the visualization could not be found.\n- `slide_not_found`, or the older `google_slide_not_found`: the slide that shows the visualization could not be found.\n- `file_not_found`: the spreadsheet file the visualization comes from could not be found.\n- `sheet_not_found`: the spreadsheet sheet could not be found.\n- `sheet_hidden`: the spreadsheet sheet is hidden and needs to be unhidden.\n- `range_not_found`: the spreadsheet range could not be found.\n- `duplicate_file_failed`: Rollstack could not prepare the spreadsheet file for the update.\n- `merged_range_on_filter_range`: the visualization has merged cells, which filters can't be applied to.\n- `insufficient_permissions`: the owner doesn't have edit access to the file.\n- `image_cropping_failed`: Rollstack could not crop the visualization's image.\n- `visualization_not_found`: the visualization could not be found in the dashboard.\n- `visualization_not_ready`: the visualization took too long to load.\n- `visualization_has_errors`: the visualization failed to load because of an error in the tool it comes from.\n- `visualization_empty`, or the older `empty_data`: the visualization is empty.\n- `invalid_credentials`: the connection's credentials are invalid.\n- `missing_credentials`: the connection's credentials were deleted, or the owner's access to it was suspended.\n- `instance_unavailable`: the data source's instance is temporarily unavailable.\n- `column_not_found`: a column the native chart uses is missing from its data.\n- `fetch_summary_data_error`, `fetch_visual_specification_error`, `missing_data`, `missing_formatted_value` and `viz_not_ready`: Rollstack could not fetch the data of a native chart.\n- `incorrect_data_structure`: the native chart's structure doesn't fit its data.\n- `malformed_data`: Rollstack could not fetch the data of a native chart or, from Snowflake or Databricks, the query is invalid.\n- `worksheet_not_found`: the Tableau worksheet could not be found.\n- `sync_not_found`: the visualization was deleted.\n- `file_update_failed`: the data was fetched but could not be written into the file."},"emailAnalyticsEnabled":{"type":"boolean","description":"Whether Rollstack tracks when recipients open the report's email; opened emails show as Opened in the report's Email sends panel in the app. Opens are tracked only while email analytics is also on for the organization (`emailAnalyticsEnabled` from `getOrganization`). Rollstack detects them through an invisible image in the email."},"createdAt":{"description":"When the report's email settings were created. Until they exist, `getReportEmailConfig` returns 404.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the report's email settings were last saved. Changes the slides agent makes to the recipients alone don't update it.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["to","cc","bcc","replyTo","groupRecipients","smtpServerId","sharingFormat","sendAttachmentAsLink","trigger","ignoredFailureStatusMessages","emailAnalyticsEnabled","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"updateReportEmailConfig","summary":"Replace email settings","description":"Sets who a report's email goes to and how it is sent, replacing the whole setup. Only its editors may. The sender must be the user's own or shared with the organization.\n\nRequires the `slide_decks:email` scope.","tags":["Email"],"x-scope":"slide_decks:email","security":[{"apiKey":[]},{"oauth2":["slide_decks:email"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"to":{"type":"array","items":{"type":"string","examples":["jane@acme.com"]},"description":"The addresses to send the report's email to. If empty, no one receives it: the report's runs send no email and `sendReportEmail` returns 400. At most 100 addresses across `to`, `cc` and `bcc`."},"cc":{"default":[],"description":"The addresses to copy on the report's email, which every recipient can see. If omitted, no one is copied. Counts toward the 100 addresses allowed across `to`, `cc` and `bcc`.","type":"array","items":{"type":"string","examples":["jane@acme.com"]}},"bcc":{"default":[],"description":"The addresses to also send the report's email to without the other recipients seeing them. If omitted, no one is blind-copied. Counts toward the 100 addresses allowed across `to`, `cc` and `bcc`.","type":"array","items":{"type":"string","examples":["jane@acme.com"]}},"replyTo":{"default":[],"description":"The addresses recipients' replies should go to instead of the sender. They don't receive the email themselves. If omitted, replies go to the sender.","type":"array","items":{"type":"string","examples":["jane@acme.com"]}},"groupRecipients":{"default":true,"description":"Whether to send one email to all the addresses in `to` together. Set it to `false` to send each address in `to` its own email with the same `cc`, `bcc` and `replyTo`; the addresses in `cc` and `bcc` then receive one copy per address in `to`. Defaults to `true`.","type":"boolean"},"smtpServerId":{"default":null,"description":"The SMTP connection to send the report's email through, from `listSmtpConnections`; recipients see its `from` address as the sender. If `null` or omitted, the email is sent from Rollstack's own address. A connection `listSmtpConnections` doesn't list, or a Google or Microsoft account Rollstack can no longer send from, returns 403 unless it is already the report's sender.","examples":["9f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"],"anyOf":[{"type":"string"},{"type":"null"}]},"sharingFormat":{"default":"pdf","description":"How the email should deliver the report. `pdf` and `ppt` send its slides, without the hidden ones, as a PDF or PowerPoint file, attached or behind a download button (see `sendAttachmentAsLink`). `cloudLink` (Exported link in the app) sends a link to the copy of the report exported to Google Drive or OneDrive, and shares that copy with the addresses in `to`, `cc` and `bcc` with the sharing permission set in the app, which this endpoint doesn't change (viewer unless changed there). If no permission is set, as after PDF or PPT was picked in the app, the copy isn't shared with them. Set up that export in the report's Update runs settings in the app: until the report has first been exported there, emails to its recipients fail to send. `link` doesn't apply to reports, which have no Google Drive or OneDrive file of their own, and returns 400. Defaults to `pdf`.","type":"string","enum":["link","pdf","ppt","cloudLink"]},"sendAttachmentAsLink":{"default":true,"description":"Whether to put the `pdf` or `ppt` file behind a Download PDF or Download PPT button in the email instead of attaching it, since some email clients alter or block attachments. Set it to `false` to attach the file. Has no effect with `cloudLink`. Defaults to `true`.","type":"boolean"},"trigger":{"default":"all","description":"Which of the report's runs should email it automatically. `all` and `scheduled` work the same way for reports: each run started by one of the report's schedules (see `updateReportSchedules`) sends the email when it updates every datasheet, or when it updates some and all its failures are in `ignoredFailureStatusMessages`. A report with no datasheets is never emailed by its runs. With `none` (Manual in the app), no run sends it: the email goes out only when sent with `sendReportEmail` or from the app. Runs started any other way, such as with `startReportRun` or from the app, never send it. Defaults to `all`.","type":"string","enum":["all","none","scheduled"]},"ignoredFailureStatusMessages":{"default":["slide_not_found"],"description":"The failures that shouldn't stop a scheduled run from emailing the report (see `trigger`). A run in which some datasheets fail still sends the email when all its failures are in this list; a run in which every datasheet fails never does. A report's run records each failed datasheet as `internal_server_error`: include it to email the report even when some of its datasheets fail. Defaults to `slide_not_found` alone, which has no effect on reports, so by default a run in which any datasheet fails sends no email.\n\nThe other values describe failures of visualizations taken from a BI dashboard, spreadsheet or data source, which a report's run never reports, so they have no effect:\n\n- `dashboard_not_found`, or the older `tableau_view_not_found`: the dashboard, Tableau workbook, Power BI report or spreadsheet could not be found.\n- `dashboard_tab_not_found`: the dashboard tab, Tableau view, Power BI report page or spreadsheet sheet could not be found.\n- `dashboard_not_ready`: the dashboard took too long to load.\n- `dashboard_has_errors`: the dashboard or spreadsheet failed to load because of an error in the tool it comes from.\n- `dashboard_invalid_layout`: the dashboard's layout is invalid, and it needs to be saved again.\n- `element_not_found`, or the older `metabase_element_not_found` and `looker_element_not_found`: the visualization could not be found.\n- `slide_not_found`, or the older `google_slide_not_found`: the slide that shows the visualization could not be found.\n- `file_not_found`: the spreadsheet file the visualization comes from could not be found.\n- `sheet_not_found`: the spreadsheet sheet could not be found.\n- `sheet_hidden`: the spreadsheet sheet is hidden and needs to be unhidden.\n- `range_not_found`: the spreadsheet range could not be found.\n- `duplicate_file_failed`: Rollstack could not prepare the spreadsheet file for the update.\n- `merged_range_on_filter_range`: the visualization has merged cells, which filters can't be applied to.\n- `insufficient_permissions`: the owner doesn't have edit access to the file.\n- `image_cropping_failed`: Rollstack could not crop the visualization's image.\n- `visualization_not_found`: the visualization could not be found in the dashboard.\n- `visualization_not_ready`: the visualization took too long to load.\n- `visualization_has_errors`: the visualization failed to load because of an error in the tool it comes from.\n- `visualization_empty`, or the older `empty_data`: the visualization is empty.\n- `invalid_credentials`: the connection's credentials are invalid.\n- `missing_credentials`: the connection's credentials were deleted, or the owner's access to it was suspended.\n- `instance_unavailable`: the data source's instance is temporarily unavailable.\n- `column_not_found`: a column the native chart uses is missing from its data.\n- `fetch_summary_data_error`, `fetch_visual_specification_error`, `missing_data`, `missing_formatted_value` and `viz_not_ready`: Rollstack could not fetch the data of a native chart.\n- `incorrect_data_structure`: the native chart's structure doesn't fit its data.\n- `malformed_data`: Rollstack could not fetch the data of a native chart or, from Snowflake or Databricks, the query is invalid.\n- `worksheet_not_found`: the Tableau worksheet could not be found.\n- `sync_not_found`: the visualization was deleted.\n- `file_update_failed`: the data was fetched but could not be written into the file.","type":"array","items":{"type":"string","enum":["tableau_view_not_found","dashboard_not_found","dashboard_tab_not_found","dashboard_not_ready","dashboard_has_errors","dashboard_invalid_layout","metabase_element_not_found","looker_element_not_found","element_not_found","google_slide_not_found","slide_not_found","file_not_found","sheet_not_found","sheet_hidden","range_not_found","duplicate_file_failed","merged_range_on_filter_range","insufficient_permissions","image_cropping_failed","visualization_not_found","visualization_not_ready","visualization_has_errors","visualization_empty","invalid_credentials","missing_credentials","instance_unavailable","column_not_found","empty_data","fetch_summary_data_error","fetch_visual_specification_error","incorrect_data_structure","missing_data","missing_formatted_value","malformed_data","viz_not_ready","worksheet_not_found","sync_not_found","file_update_failed","internal_server_error"]}},"emailAnalyticsEnabled":{"default":false,"description":"Whether to track when recipients open the report's email; opened emails show as Opened in the report's Email sends panel in the app. Setting it to `true` returns 403 unless email analytics is on for the organization (`emailAnalyticsEnabled` from `getOrganization`). Defaults to `false`.","type":"boolean"}},"required":["to"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"to":{"type":"array","items":{"type":"string"},"description":"The addresses the report's email is sent to. When empty, no one receives it: the report's runs send no email and `sendReportEmail` returns 400."},"cc":{"type":"array","items":{"type":"string"},"description":"The addresses copied on the report's email, which every recipient can see."},"bcc":{"type":"array","items":{"type":"string"},"description":"The addresses that also receive the report's email without the other recipients seeing them."},"replyTo":{"type":"array","items":{"type":"string"},"description":"The addresses recipients' replies go to instead of the sender. They don't receive the email themselves. Empty when replies go to the sender."},"groupRecipients":{"type":"boolean","description":"Whether all the addresses in `to` receive one email together. When `false`, each address in `to` gets its own email with the same `cc`, `bcc` and `replyTo`, so the addresses in `cc` and `bcc` receive one copy per address in `to`."},"smtpServerId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The SMTP connection the report's email is sent through, from `listSmtpConnections`; recipients see its `from` address as the sender. `null` when the email is sent from Rollstack's own address."},"sharingFormat":{"type":"string","enum":["link","pdf","ppt","cloudLink"],"description":"How the email delivers the report. `pdf` and `ppt` send its slides, without the hidden ones, as a PDF or PowerPoint file, attached or behind a download button (see `sendAttachmentAsLink`). `cloudLink` (Exported link in the app) sends a link to the copy of the report exported to Google Drive or OneDrive, and shares that copy with the addresses in `to`, `cc` and `bcc` with the sharing permission set in the app, viewer unless changed there. If no permission is set, as after PDF or PPT was picked in the app, the copy isn't shared with them. `link` isn't available for reports: a report whose settings still contain it is emailed as a PDF behind a download button."},"sendAttachmentAsLink":{"type":"boolean","description":"Whether the email puts the `pdf` or `ppt` file behind a Download PDF or Download PPT button instead of attaching it. When `false`, the file is attached. Has no effect with `cloudLink`."},"trigger":{"type":"string","enum":["all","none","scheduled"],"description":"Which of the report's runs email it automatically. `all` and `scheduled` work the same way for reports: each run started by one of the report's schedules (see `getReportSchedules`) sends the email when it updates every datasheet, or when it updates some and all its failures are in `ignoredFailureStatusMessages`. A report with no datasheets is never emailed by its runs. With `none` (Manual in the app), no run sends it: the email goes out only when sent with `sendReportEmail` or from the app. Runs started any other way, such as with `startReportRun` or from the app, never send it."},"ignoredFailureStatusMessages":{"type":"array","items":{"type":"string","enum":["tableau_view_not_found","dashboard_not_found","dashboard_tab_not_found","dashboard_not_ready","dashboard_has_errors","dashboard_invalid_layout","metabase_element_not_found","looker_element_not_found","element_not_found","google_slide_not_found","slide_not_found","file_not_found","sheet_not_found","sheet_hidden","range_not_found","duplicate_file_failed","merged_range_on_filter_range","insufficient_permissions","image_cropping_failed","visualization_not_found","visualization_not_ready","visualization_has_errors","visualization_empty","invalid_credentials","missing_credentials","instance_unavailable","column_not_found","empty_data","fetch_summary_data_error","fetch_visual_specification_error","incorrect_data_structure","missing_data","missing_formatted_value","malformed_data","viz_not_ready","worksheet_not_found","sync_not_found","file_update_failed","internal_server_error"]},"description":"The failures that don't stop a scheduled run from emailing the report (see `trigger`). A run in which some datasheets fail still sends the email when all its failures are in this list; a run in which every datasheet fails never does. A report's run records each failed datasheet as `internal_server_error`, so that is the only value with an effect: when it is listed, a run in which only some datasheets fail sends the email.\n\nThe other values describe failures of visualizations taken from a BI dashboard, spreadsheet or data source, which a report's run never reports, so they have no effect:\n\n- `dashboard_not_found`, or the older `tableau_view_not_found`: the dashboard, Tableau workbook, Power BI report or spreadsheet could not be found.\n- `dashboard_tab_not_found`: the dashboard tab, Tableau view, Power BI report page or spreadsheet sheet could not be found.\n- `dashboard_not_ready`: the dashboard took too long to load.\n- `dashboard_has_errors`: the dashboard or spreadsheet failed to load because of an error in the tool it comes from.\n- `dashboard_invalid_layout`: the dashboard's layout is invalid, and it needs to be saved again.\n- `element_not_found`, or the older `metabase_element_not_found` and `looker_element_not_found`: the visualization could not be found.\n- `slide_not_found`, or the older `google_slide_not_found`: the slide that shows the visualization could not be found.\n- `file_not_found`: the spreadsheet file the visualization comes from could not be found.\n- `sheet_not_found`: the spreadsheet sheet could not be found.\n- `sheet_hidden`: the spreadsheet sheet is hidden and needs to be unhidden.\n- `range_not_found`: the spreadsheet range could not be found.\n- `duplicate_file_failed`: Rollstack could not prepare the spreadsheet file for the update.\n- `merged_range_on_filter_range`: the visualization has merged cells, which filters can't be applied to.\n- `insufficient_permissions`: the owner doesn't have edit access to the file.\n- `image_cropping_failed`: Rollstack could not crop the visualization's image.\n- `visualization_not_found`: the visualization could not be found in the dashboard.\n- `visualization_not_ready`: the visualization took too long to load.\n- `visualization_has_errors`: the visualization failed to load because of an error in the tool it comes from.\n- `visualization_empty`, or the older `empty_data`: the visualization is empty.\n- `invalid_credentials`: the connection's credentials are invalid.\n- `missing_credentials`: the connection's credentials were deleted, or the owner's access to it was suspended.\n- `instance_unavailable`: the data source's instance is temporarily unavailable.\n- `column_not_found`: a column the native chart uses is missing from its data.\n- `fetch_summary_data_error`, `fetch_visual_specification_error`, `missing_data`, `missing_formatted_value` and `viz_not_ready`: Rollstack could not fetch the data of a native chart.\n- `incorrect_data_structure`: the native chart's structure doesn't fit its data.\n- `malformed_data`: Rollstack could not fetch the data of a native chart or, from Snowflake or Databricks, the query is invalid.\n- `worksheet_not_found`: the Tableau worksheet could not be found.\n- `sync_not_found`: the visualization was deleted.\n- `file_update_failed`: the data was fetched but could not be written into the file."},"emailAnalyticsEnabled":{"type":"boolean","description":"Whether Rollstack tracks when recipients open the report's email; opened emails show as Opened in the report's Email sends panel in the app. Opens are tracked only while email analytics is also on for the organization (`emailAnalyticsEnabled` from `getOrganization`). Rollstack detects them through an invisible image in the email."},"createdAt":{"description":"When the report's email settings were created. Until they exist, `getReportEmailConfig` returns 404.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the report's email settings were last saved. Changes the slides agent makes to the recipients alone don't update it.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["to","cc","bcc","replyTo","groupRecipients","smtpServerId","sharingFormat","sendAttachmentAsLink","trigger","ignoredFailureStatusMessages","emailAnalyticsEnabled","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/emails":{"post":{"operationId":"sendReportEmail","summary":"Send email","description":"Emails a report to its recipients now, as it is. Only its editors may. Answers 400 when it has no recipients. Sends in the background; while the user's send of the report is going, starts nothing. At most 5 sends a minute per user, test sends included.\n\nRequires the `slide_decks:email` scope.","tags":["Email"],"x-scope":"slide_decks:email","security":[{"apiKey":[]},{"oauth2":["slide_decks:email"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":true},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}}],"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/{id}/emails/test":{"post":{"operationId":"sendReportTestEmail","summary":"Send test email","description":"Sends a report's email to the user only, and waits until it is sent. Only its editors may. Counts against the 5 sends a minute.\n\nRequires the `slide_decks:email` scope.","tags":["Email"],"x-scope":"slide_decks:email","security":[{"apiKey":[]},{"oauth2":["slide_decks:email"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":true},"parameters":[{"name":"id","in":"path","required":true,"description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`.","schema":{"type":"string","description":"The report to act on, by its `id` from `listReports` or `createReport`. Only reports whose `type` is `SlideDeck` work here: another type, such as a Google Slides presentation, returns `400`. You can also copy it from the report's link in Rollstack: it's the part right after `/slides/`."}}],"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bursts":{"get":{"operationId":"listBursts","summary":"List bursts","description":"The bursts of reports the user can see, newest first, with the report parameters their variants differ by and the template report they are copied from. You can filter by name, ignoring case. Answers up to limit bursts, 50 by default and 200 at most, and a nextCursor: pass it as cursor for the next page, until it is null. listReports leaves out the reports of a burst, its template and variants.\n\nRequires the `slide_decks:read` scope.","tags":["Bursts"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"name","in":"query","required":false,"description":"Only return bursts whose name contains this text, ignoring case: `region` matches `Regional Review`.","schema":{"description":"Only return bursts whose name contains this text, ignoring case: `region` matches `Regional Review`.","examples":["regional"],"type":"string","minLength":1}},{"name":"limit","in":"query","required":false,"description":"Maximum number of bursts to return on this page, from 1 to 200. Defaults to `50`.","schema":{"default":50,"description":"Maximum number of bursts to return on this page, from 1 to 200. Defaults to `50`.","type":"integer","minimum":1,"maximum":200}},{"name":"cursor","in":"query","required":false,"description":"Where to continue the list: pass the `nextCursor` returned with the previous page to get the next one. Omit it for the first page.","schema":{"description":"Where to continue the list: pass the `nextCursor` returned with the previous page to get the next one. Omit it for the first page.","examples":["6c1f9a2e-3b4d-4e8f-9a1b-2c3d4e5f6a7b"],"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the burst. Pass it as `id` to the other `/bursts/{id}` endpoints."},"name":{"type":"string","description":"Name of the burst, as members see it in Rollstack. It is the template report's name when the burst is created, and is part of each variant report's name unless `variantNaming` is `sameName`."},"folderId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The folder the burst is in, by its `id` in `listFolders`. `null` when the burst is at the top level."},"owner":{"type":"object","properties":{"id":{"type":"number","description":"The owner's user id, the same as their `id` in `listMembers`."},"name":{"type":"string","description":"The owner's name, as shown in Rollstack."},"email":{"type":"string","description":"The owner's email address."}},"required":["id","name","email"],"additionalProperties":false,"description":"The member who owns the burst: whoever created it, unless ownership has since been transferred in the app."},"templateReportId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The template report, which every variant was copied from when it was added, by its `id` for `getReport` and the other `/reports/{id}` endpoints. Changes to the template reach existing variants only when pushed from the app; variants added later copy it as it is then. `null` if the template was deleted."},"variantNaming":{"type":"string","enum":["sameName","prefix","suffix"],"description":"How each variant's report is named from the burst's name and the name the variant is added with, `EMEA` in a burst named `Regional Review`: `suffix` gives `Regional Review - EMEA`, `prefix` gives `EMEA - Regional Review`, and `sameName` gives `EMEA`. It applies to variants added from then on."},"parameters":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The report parameter's id on the template report. Use it as a key of `parameters` in `addBurstVariants`."},"name":{"type":"string","description":"The report parameter's name, as shown in Rollstack."},"value":{"anyOf":[{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"categorical"},"values":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"operator":{"type":"string","enum":["is","is_not","contains","doesnt_contain"]}},"required":["type","values"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_range"},"startDate":{"type":"string"},"endDate":{"type":"string"}},"required":["type","subtype","startDate","endDate"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_relative"},"rangeType":{"type":"string","enum":["current","lastN","nextN"]},"rangeN":{"type":"number"},"periodType":{"type":"string","enum":["days","weeks","months","quarters","years","completeDays","completeWeeks","completeMonths","completeQuarters","completeYears"]}},"required":["type","subtype","rangeType","rangeN","periodType"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_month_year"},"month":{"type":"number"},"year":{"type":"number"}},"required":["type","subtype","month","year"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_quarter_year"},"quarter":{"type":"number"},"year":{"type":"number"}},"required":["type","subtype","quarter","year"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_single"},"date":{"type":"string"}},"required":["type","subtype","date"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_null"}},"required":["type","subtype"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"number"},"value":{"type":"number"}},"required":["type","value"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"text"},"value":{"type":"string","minLength":1}},"required":["type","value"],"additionalProperties":false}]},{"type":"null"}],"description":"The template's value of the parameter, which a variant keeps when it doesn't set one. `null` when the template has none. A value of a report parameter, in the shape of its type. Copy the shape of the parameter's `value` in `listBursts`, or of a variant's in `listBurstVariants`:\n\n- A list of values: `{ \"type\": \"categorical\", \"values\": [\"EMEA\"] }`, with at least one value. `operator` can also be `is_not`, `contains` or `doesnt_contain`; it is `is` when left out.\n- A number: `{ \"type\": \"number\", \"value\": 10 }`. Text: `{ \"type\": \"text\", \"value\": \"EMEA\" }`.\n- A date range: `{ \"type\": \"date\", \"subtype\": \"date_range\", \"startDate\": \"2026-01-01\", \"endDate\": \"2026-03-31\" }`. One date: `{ \"type\": \"date\", \"subtype\": \"date_single\", \"date\": \"2026-03-31\" }`.\n- A month or a quarter: `{ \"type\": \"date\", \"subtype\": \"date_month_year\", \"month\": 3, \"year\": 2026 }` (months 1 to 12), `{ \"type\": \"date\", \"subtype\": \"date_quarter_year\", \"quarter\": 1, \"year\": 2026 }`.\n- A relative period: `{ \"type\": \"date\", \"subtype\": \"date_relative\", \"rangeType\": \"lastN\", \"rangeN\": 3, \"periodType\": \"months\" }`. `rangeType` is `current`, `lastN` or `nextN`; `periodType` is `days`, `weeks`, `months`, `quarters` or `years`, or `completeDays` through `completeYears` for whole periods only."}},"required":["id","name","value"],"additionalProperties":false},"description":"The template report's parameters the variants differ by, in the order their values name a variant. Each variant holds its own value of each, which its datasheets' filters read."},"variantCount":{"type":"number","description":"How many variants the burst has, including any you can't open."},"appUrl":{"type":"string","format":"uri","description":"Link that opens the burst in Rollstack."},"createdAt":{"description":"When the burst was created. `listBursts` returns the newest first.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the burst's details last changed.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","name","folderId","owner","templateReportId","variantNaming","parameters","variantCount","appUrl","createdAt","updatedAt"],"additionalProperties":false},"description":"The bursts on this page, most recently created first."},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass it as `cursor` to get the next page of bursts. `null` when there are no more."}},"required":["data","nextCursor"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createBurst","summary":"Create burst","description":"Makes a report the template of a new burst whose variants differ by the report parameters given, and answers the burst, named after the report and with no variants yet. Add them with addBurstVariants. Only the report's editors may.\n\nRequires the `slide_decks:write` scope.","tags":["Bursts"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"templateReportId":{"type":"string","description":"The report to make the template of the burst, by its `id` from `listReports`. You must be able to edit it, it must have datasheets, and it can't already be part of a burst. It becomes the template as it is: no copy is made.","examples":["6c1f9a2e-3b4d-4e8f-9a1b-2c3d4e5f6a7b"]},"parameterIds":{"minItems":1,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","examples":["5e7a9c1b-3d5f-4b7d-9e1a-3c5e7a9b1d3f"]},"description":"The template report's parameters the variants differ by, by their `id` from `getReportParameters`, in the order their values name a variant. Each must be `burstable` there. At least one."},"variantNaming":{"default":"suffix","description":"How each variant's report is named from the burst's name and the name the variant is added with, `EMEA` in a burst named `Regional Review`: `suffix` gives `Regional Review - EMEA`, `prefix` gives `EMEA - Regional Review`, and `sameName` gives `EMEA`. It applies to variants added from then on. Defaults to `suffix`.","type":"string","enum":["sameName","prefix","suffix"]}},"required":["templateReportId","parameterIds"],"additionalProperties":false}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the burst. Pass it as `id` to the other `/bursts/{id}` endpoints."},"name":{"type":"string","description":"Name of the burst, as members see it in Rollstack. It is the template report's name when the burst is created, and is part of each variant report's name unless `variantNaming` is `sameName`."},"folderId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The folder the burst is in, by its `id` in `listFolders`. `null` when the burst is at the top level."},"owner":{"type":"object","properties":{"id":{"type":"number","description":"The owner's user id, the same as their `id` in `listMembers`."},"name":{"type":"string","description":"The owner's name, as shown in Rollstack."},"email":{"type":"string","description":"The owner's email address."}},"required":["id","name","email"],"additionalProperties":false,"description":"The member who owns the burst: whoever created it, unless ownership has since been transferred in the app."},"templateReportId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The template report, which every variant was copied from when it was added, by its `id` for `getReport` and the other `/reports/{id}` endpoints. Changes to the template reach existing variants only when pushed from the app; variants added later copy it as it is then. `null` if the template was deleted."},"variantNaming":{"type":"string","enum":["sameName","prefix","suffix"],"description":"How each variant's report is named from the burst's name and the name the variant is added with, `EMEA` in a burst named `Regional Review`: `suffix` gives `Regional Review - EMEA`, `prefix` gives `EMEA - Regional Review`, and `sameName` gives `EMEA`. It applies to variants added from then on."},"parameters":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The report parameter's id on the template report. Use it as a key of `parameters` in `addBurstVariants`."},"name":{"type":"string","description":"The report parameter's name, as shown in Rollstack."},"value":{"anyOf":[{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"categorical"},"values":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"operator":{"type":"string","enum":["is","is_not","contains","doesnt_contain"]}},"required":["type","values"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_range"},"startDate":{"type":"string"},"endDate":{"type":"string"}},"required":["type","subtype","startDate","endDate"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_relative"},"rangeType":{"type":"string","enum":["current","lastN","nextN"]},"rangeN":{"type":"number"},"periodType":{"type":"string","enum":["days","weeks","months","quarters","years","completeDays","completeWeeks","completeMonths","completeQuarters","completeYears"]}},"required":["type","subtype","rangeType","rangeN","periodType"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_month_year"},"month":{"type":"number"},"year":{"type":"number"}},"required":["type","subtype","month","year"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_quarter_year"},"quarter":{"type":"number"},"year":{"type":"number"}},"required":["type","subtype","quarter","year"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_single"},"date":{"type":"string"}},"required":["type","subtype","date"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_null"}},"required":["type","subtype"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"number"},"value":{"type":"number"}},"required":["type","value"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"text"},"value":{"type":"string","minLength":1}},"required":["type","value"],"additionalProperties":false}]},{"type":"null"}],"description":"The template's value of the parameter, which a variant keeps when it doesn't set one. `null` when the template has none. A value of a report parameter, in the shape of its type. Copy the shape of the parameter's `value` in `listBursts`, or of a variant's in `listBurstVariants`:\n\n- A list of values: `{ \"type\": \"categorical\", \"values\": [\"EMEA\"] }`, with at least one value. `operator` can also be `is_not`, `contains` or `doesnt_contain`; it is `is` when left out.\n- A number: `{ \"type\": \"number\", \"value\": 10 }`. Text: `{ \"type\": \"text\", \"value\": \"EMEA\" }`.\n- A date range: `{ \"type\": \"date\", \"subtype\": \"date_range\", \"startDate\": \"2026-01-01\", \"endDate\": \"2026-03-31\" }`. One date: `{ \"type\": \"date\", \"subtype\": \"date_single\", \"date\": \"2026-03-31\" }`.\n- A month or a quarter: `{ \"type\": \"date\", \"subtype\": \"date_month_year\", \"month\": 3, \"year\": 2026 }` (months 1 to 12), `{ \"type\": \"date\", \"subtype\": \"date_quarter_year\", \"quarter\": 1, \"year\": 2026 }`.\n- A relative period: `{ \"type\": \"date\", \"subtype\": \"date_relative\", \"rangeType\": \"lastN\", \"rangeN\": 3, \"periodType\": \"months\" }`. `rangeType` is `current`, `lastN` or `nextN`; `periodType` is `days`, `weeks`, `months`, `quarters` or `years`, or `completeDays` through `completeYears` for whole periods only."}},"required":["id","name","value"],"additionalProperties":false},"description":"The template report's parameters the variants differ by, in the order their values name a variant. Each variant holds its own value of each, which its datasheets' filters read."},"variantCount":{"type":"number","description":"How many variants the burst has, including any you can't open."},"appUrl":{"type":"string","format":"uri","description":"Link that opens the burst in Rollstack."},"createdAt":{"description":"When the burst was created. `listBursts` returns the newest first.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the burst's details last changed.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","name","folderId","owner","templateReportId","variantNaming","parameters","variantCount","appUrl","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bursts/{id}/variants":{"get":{"operationId":"listBurstVariants","summary":"List burst variants","description":"A burst's variants the user can open, oldest first, each with its values of the burst's parameters, how its latest run went, whether one is going, and who its email goes to. adding lists the variants the user is still adding. Answers up to limit variants, 50 by default and 200 at most, and a nextCursor: pass it as cursor for the next page, until it is null.\n\nRequires the `slide_decks:read` scope.","tags":["Bursts"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The burst to act on, by its `id` from `listBursts`. You can also copy it from the burst's link in Rollstack: it's the part right after `/collections/`.","schema":{"type":"string","description":"The burst to act on, by its `id` from `listBursts`. You can also copy it from the burst's link in Rollstack: it's the part right after `/collections/`."}},{"name":"limit","in":"query","required":false,"description":"Maximum number of variants to return on this page, from 1 to 200. Defaults to `50`.","schema":{"default":50,"description":"Maximum number of variants to return on this page, from 1 to 200. Defaults to `50`.","type":"integer","minimum":1,"maximum":200}},{"name":"cursor","in":"query","required":false,"description":"Where to continue the list: pass the `nextCursor` returned with the previous page to get the next one. Omit it for the first page.","schema":{"description":"Where to continue the list: pass the `nextCursor` returned with the previous page to get the next one. Omit it for the first page.","examples":["6c1f9a2e-3b4d-4e8f-9a1b-2c3d4e5f6a7b"],"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the report. Pass it as `id` to the other `/reports/{id}` endpoints."},"type":{"type":"string","enum":["GoogleDocs","GoogleSlides","MicrosoftPowerPoint","MicrosoftWord","Email","UploadedPPTXFile","SlideDeck"],"description":"The kind of report, which decides the endpoints that work on it.\n\n- `SlideDeck`: a slide deck built in Rollstack. Every `/reports/{id}` endpoint works on it.\n- `GoogleSlides`, `GoogleDocs`, `MicrosoftPowerPoint`, `MicrosoftWord`: a file in Google Drive or OneDrive that Rollstack updates with its visualizations.\n- `UploadedPPTXFile`: a PowerPoint file uploaded to Rollstack, which it updates the same way.\n- `Email`: an email report, whose visualizations Rollstack sends in an email.\n\nOn a report that isn't a `SlideDeck`, only `getReport`, `updateReport`, `deleteReport`, `shareReport`, `unshareReport`, `getReportSchedules`, `updateReportSchedules`, `startReportRun`, `getReportRun` and `cancelReportRun` work. The other `/reports/{id}` endpoints take `SlideDeck` reports only, as their `id` says, and return `400`."},"name":{"type":"string","description":"Name of the report, as members see it in Rollstack. Change it with `updateReport`."},"folderId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The folder the report is in, by its `id` in `listFolders`. `null` when the report is at the top level, outside any folder."},"owner":{"type":"object","properties":{"id":{"type":"number","description":"The owner's user id, the same as their `id` in `listMembers`."},"name":{"type":"string","description":"The owner's name, as shown in Rollstack."},"email":{"type":"string","description":"The owner's email address. Rollstack emails this address when a scheduled run of the report fails, while `notifyOnFailure` is `true`."}},"required":["id","name","email"],"additionalProperties":false,"description":"The member who owns the report: whoever created it, unless ownership has since been transferred, in the app or with `transferReportOwnership`. Only the owner can delete the report."},"permission":{"anyOf":[{"type":"string","enum":["view","comment","edit"]},{"type":"null"}],"description":"Your access to the report, as the user the API key belongs to. `view` lets you open and export it, and see its datasheets, runs, schedules and email setup. `comment` also lets you add, reply to and resolve comments on its slides. `edit` also lets you change it: rename or move it, chat with the slides agent about it, add datasheets and read their data, start runs, set its schedules and email, send its email, and share it. It's never `null` here, since the API only returns reports you can at least view."},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The report's timezone, such as `America/New_York`. The slides agent uses it to tell today's date, and the report's emails show the time of its last successful update (`{{last_updated_at}}`) in it. On a report that updates a file, such as a Google Slides presentation, it's also the timezone of the file's date variables, unless the organization's `timezone` replaces it. Schedules don't use it: each has its own `timezone`. `null` when the report has none, in which case the slides agent uses UTC. Reports created with `createReport` start with the organization's `timezone` from `getOrganization`, if it has one."},"notifyOnFailure":{"type":"boolean","description":"Whether Rollstack emails the report's owner when a scheduled run fails or some of its datasheets, or a file's visualizations, fail to refresh, copying everyone in `notificationMailingList`. Runs started in the app or with `startReportRun` never send this email. New reports start with `true`."},"lastSyncedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the report's latest run ended, whatever its outcome. `null` if the report has never run."},"lastSuccessfulUpdateAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the report's latest fully successful run ended: one that refreshed every datasheet it ran on, or every visualization on a report that updates a file, with none failing. Runs with nothing to refresh don't count. The report's emails show this time as `{{last_updated_at}}`. `null` until the report has had such a run."},"lastRunStatus":{"anyOf":[{"type":"string","enum":["running","completed","failed","cancelled","timed_out"]},{"type":"null"}],"description":"How the report's latest run ended. `completed`: it finished, even if some datasheets or visualizations failed to refresh or it had none to refresh; on a `SlideDeck` report, `listReportDatasheets` shows each datasheet's `error`. `failed`: it stopped on an error, or none of its datasheets or visualizations could be refreshed. `cancelled`: it was stopped before it finished, for example with `cancelReportRun`. `null` if the report has never run. `running` and `timed_out` never appear here: check `running` to see whether a run is in progress."},"running":{"type":"boolean","description":"Whether a run of the report is in progress, whoever started it, such as you with `startReportRun`, a member in the app, or one of its schedules. While it's `true`, `startReportRun` returns that run instead of starting another."},"appUrl":{"type":"string","format":"uri","description":"Link that opens the report in Rollstack."},"createdAt":{"description":"When the report was created. `listReports` returns the newest first.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the report's details last changed, such as its name, folder or owner, or the outcome of its latest run.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"parameters":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The report parameter's id on the template report. Use it as a key of `parameters` in `addBurstVariants`."},"name":{"type":"string","description":"The report parameter's name, as shown in Rollstack."},"value":{"anyOf":[{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"categorical"},"values":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"operator":{"type":"string","enum":["is","is_not","contains","doesnt_contain"]}},"required":["type","values"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_range"},"startDate":{"type":"string"},"endDate":{"type":"string"}},"required":["type","subtype","startDate","endDate"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_relative"},"rangeType":{"type":"string","enum":["current","lastN","nextN"]},"rangeN":{"type":"number"},"periodType":{"type":"string","enum":["days","weeks","months","quarters","years","completeDays","completeWeeks","completeMonths","completeQuarters","completeYears"]}},"required":["type","subtype","rangeType","rangeN","periodType"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_month_year"},"month":{"type":"number"},"year":{"type":"number"}},"required":["type","subtype","month","year"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_quarter_year"},"quarter":{"type":"number"},"year":{"type":"number"}},"required":["type","subtype","quarter","year"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_single"},"date":{"type":"string"}},"required":["type","subtype","date"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_null"}},"required":["type","subtype"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"number"},"value":{"type":"number"}},"required":["type","value"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"text"},"value":{"type":"string","minLength":1}},"required":["type","value"],"additionalProperties":false}]},{"type":"null"}],"description":"The value the variant holds: the one it was added with, or the template's when it set none. `null` when neither had one."}},"required":["id","name","value"],"additionalProperties":false},"description":"The variant's value of each parameter the burst varies by, in the burst's order."},"recipients":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string"},"description":"The addresses the report's email is sent to. When empty, no one receives it: the report's runs send no email and `sendReportEmail` returns 400."},"cc":{"type":"array","items":{"type":"string"},"description":"The addresses copied on the report's email, which every recipient can see."},"bcc":{"type":"array","items":{"type":"string"},"description":"The addresses that also receive the report's email without the other recipients seeing them."}},"required":["to","cc","bcc"],"additionalProperties":false,"description":"Who the variant's email goes to, all empty until it is set up. Set them with `updateBurstVariantRecipients`."}},"required":["id","type","name","folderId","owner","permission","timezone","notifyOnFailure","lastSyncedAt","lastSuccessfulUpdateAt","lastRunStatus","running","appUrl","createdAt","updatedAt","parameters","recipients"],"additionalProperties":false},"description":"The variants on this page that you can open, oldest first. Each variant is a report: pass its `id` to `getReport`, `getReportContent`, `startReportRun` and the other `/reports/{id}` endpoints. `running` and `lastRunStatus` tell where its runs stand."},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass it as `cursor` to get the next page of variants. `null` when there are no more."},"adding":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"The name the variant is added with, as `addBurstVariants` returned it."},"status":{"type":"string","enum":["queued","running","completed","failed","cancelled"],"description":"Where adding it stands. `queued`: it waits for the variants before it. `running`: its report is being copied from the template and run for the first time. `completed`: it is in `data`, though its first run may have failed, as its `lastRunStatus` says. `failed`: it could not be added, and `error` says why. `cancelled`: it was cancelled in the app before it was added."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Why the variant couldn't be added, while `status` is `failed`."}},"required":["name","status","error"],"additionalProperties":false},"description":"The variants you are adding with `addBurstVariants` or in the app, while that is still going. Empty once every one is done, so call `listBurstVariants` again until it is, then look for them in `data`."}},"required":["data","nextCursor","adding"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"addBurstVariants","summary":"Add burst variants","description":"Adds variants to a burst by their values of its report parameters: each is a copy of the template report that reads its datasheets with its own values, then runs once to fetch its data. Values are checked first, so a request with one the template's filters can't take adds nothing. Answers at once with the names the variants are added with; follow them in adding from listBurstVariants.\n\nRequires the `slide_decks:write` scope.","tags":["Bursts"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The burst to act on, by its `id` from `listBursts`. You can also copy it from the burst's link in Rollstack: it's the part right after `/collections/`.","schema":{"type":"string","description":"The burst to act on, by its `id` from `listBursts`. You can also copy it from the burst's link in Rollstack: it's the part right after `/collections/`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"variants":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"object","properties":{"name":{"description":"The variant's name, which its report's name is built from as the burst's `variantNaming` says. If omitted, it is named after the values it sets, like `EMEA - Q1 2026`.","type":"string","minLength":1},"parameters":{"type":"object","propertyNames":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","examples":["5e7a9c1b-3d5f-4b7d-9e1a-3c5e7a9b1d3f"]},"additionalProperties":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"categorical"},"values":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"operator":{"type":"string","enum":["is","is_not","contains","doesnt_contain"]}},"required":["type","values"]},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_range"},"startDate":{"type":"string"},"endDate":{"type":"string"}},"required":["type","subtype","startDate","endDate"]},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_relative"},"rangeType":{"type":"string","enum":["current","lastN","nextN"]},"rangeN":{"type":"number"},"periodType":{"type":"string","enum":["days","weeks","months","quarters","years","completeDays","completeWeeks","completeMonths","completeQuarters","completeYears"]}},"required":["type","subtype","rangeType","rangeN","periodType"]},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_month_year"},"month":{"type":"number"},"year":{"type":"number"}},"required":["type","subtype","month","year"]},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_quarter_year"},"quarter":{"type":"number"},"year":{"type":"number"}},"required":["type","subtype","quarter","year"]},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_single"},"date":{"type":"string"}},"required":["type","subtype","date"]},{"type":"object","properties":{"type":{"type":"string","const":"date"},"subtype":{"type":"string","const":"date_null"}},"required":["type","subtype"]},{"type":"object","properties":{"type":{"type":"string","const":"number"},"value":{"type":"number"}},"required":["type","value"]},{"type":"object","properties":{"type":{"type":"string","const":"text"},"value":{"type":"string","minLength":1}},"required":["type","value"]}],"description":"A value of a report parameter, in the shape of its type. Copy the shape of the parameter's `value` in `listBursts`, or of a variant's in `listBurstVariants`:\n\n- A list of values: `{ \"type\": \"categorical\", \"values\": [\"EMEA\"] }`, with at least one value. `operator` can also be `is_not`, `contains` or `doesnt_contain`; it is `is` when left out.\n- A number: `{ \"type\": \"number\", \"value\": 10 }`. Text: `{ \"type\": \"text\", \"value\": \"EMEA\" }`.\n- A date range: `{ \"type\": \"date\", \"subtype\": \"date_range\", \"startDate\": \"2026-01-01\", \"endDate\": \"2026-03-31\" }`. One date: `{ \"type\": \"date\", \"subtype\": \"date_single\", \"date\": \"2026-03-31\" }`.\n- A month or a quarter: `{ \"type\": \"date\", \"subtype\": \"date_month_year\", \"month\": 3, \"year\": 2026 }` (months 1 to 12), `{ \"type\": \"date\", \"subtype\": \"date_quarter_year\", \"quarter\": 1, \"year\": 2026 }`.\n- A relative period: `{ \"type\": \"date\", \"subtype\": \"date_relative\", \"rangeType\": \"lastN\", \"rangeN\": 3, \"periodType\": \"months\" }`. `rangeType` is `current`, `lastN` or `nextN`; `periodType` is `days`, `weeks`, `months`, `quarters` or `years`, or `completeDays` through `completeYears` for whole periods only."},"examples":[{"5e7a9c1b-3d5f-4b7d-9e1a-3c5e7a9b1d3f":{"type":"categorical","values":["EMEA"]}}],"description":"The value the variant sets of each report parameter, by its `id` in the burst's `parameters`. A parameter left out keeps the template's value. A value must be one the template's datasheet filters can take, or the request returns 400 and adds nothing."}},"required":["parameters"],"additionalProperties":false},"description":"The variants to add, 1 to 500. Variants may hold the same values as one another or as an existing variant: each is added as its own report."}},"required":["variants"],"additionalProperties":false}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"variants":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"The name the variant is added with."}},"required":["name"],"additionalProperties":false},"description":"The variants being added, in the order sent. Follow them in `adding` from `listBurstVariants` until they are done."}},"required":["variants"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bursts/{id}/runs":{"post":{"operationId":"startBurstRun","summary":"Run burst variants","description":"Starts a run of every variant of a burst, or of the variants passed, as startReportRun does for each: it refreshes the variant's data and repairs its slides with AI. The template report isn't run; run it with startReportRun. Answers each variant's run at once: follow them in listBurstVariants, whose running and lastRunStatus tell where each stands, or one by one with getReportRun. A variant already running answers that run and starts nothing.\n\nRequires the `slide_decks:run` scope.","tags":["Bursts"],"x-scope":"slide_decks:run","security":[{"apiKey":[]},{"oauth2":["slide_decks:run"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The burst to act on, by its `id` from `listBursts`. You can also copy it from the burst's link in Rollstack: it's the part right after `/collections/`.","schema":{"type":"string","description":"The burst to act on, by its `id` from `listBursts`. You can also copy it from the burst's link in Rollstack: it's the part right after `/collections/`."}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","default":{},"type":"object","properties":{"variantIds":{"description":"The variants to run, by their `id` in `listBurstVariants`, instead of every variant, such as those whose last run failed. Each must be a variant of this burst. 1 to 500 ids.","minItems":1,"maxItems":500,"type":"array","items":{"type":"string"}}},"additionalProperties":false}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"runs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The variant's report id."},"name":{"type":"string","description":"The variant's report name."},"runId":{"type":"string","description":"The variant's run. Pass it with the variant's `id` to `getReportRun` or `cancelReportRun`."},"started":{"type":"boolean","description":"Whether this request started the run. `false` when a run of the variant was already going, whoever started it; `runId` is then that run's."}},"required":["id","name","runId","started"],"additionalProperties":false},"description":"The variants running, each as a run of its own report."},"failed":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The variant's report id."},"name":{"type":"string","description":"The variant's report name."},"code":{"type":"string","description":"Why its run could not start, as an error code, such as `forbidden`."},"message":{"type":"string","description":"Why its run could not start, in words."}},"required":["id","name","code","message"],"additionalProperties":false},"description":"The variants whose run could not start, such as those you can't run since you only contribute to the burst. The others still started."}},"required":["runs","failed"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bursts/{id}/variants/recipients":{"put":{"operationId":"updateBurstVariantRecipients","summary":"Set variant recipients","description":"Sets who each variant's email goes to, replacing its to, cc and bcc. Its other email settings, such as its sender and which runs send it, stay as copied from the template; a variant without email settings gets the defaults. Sends no email. As in the app, the burst's owner and admins can set any variant's recipients, other members only those of variants they own or can edit; the others are skipped, as is a variant with several recipient groups, which the app asks to reconcile first.\n\nRequires the `slide_decks:email` scope.","tags":["Bursts"],"x-scope":"slide_decks:email","security":[{"apiKey":[]},{"oauth2":["slide_decks:email"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The burst to act on, by its `id` from `listBursts`. You can also copy it from the burst's link in Rollstack: it's the part right after `/collections/`.","schema":{"type":"string","description":"The burst to act on, by its `id` from `listBursts`. You can also copy it from the burst's link in Rollstack: it's the part right after `/collections/`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"variants":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The variant, by its `id` in `listBurstVariants`."},"to":{"type":"array","items":{"type":"string","examples":["jane@acme.com"]},"description":"The addresses to send the variant's email to. If empty, no one receives it. At most 100 addresses across `to`, `cc` and `bcc`."},"cc":{"default":[],"description":"The addresses to copy on the variant's email, which every recipient can see. If omitted, no one is copied.","type":"array","items":{"type":"string","examples":["jane@acme.com"]}},"bcc":{"default":[],"description":"The addresses to also send the variant's email to without the other recipients seeing them. If omitted, no one is blind-copied.","type":"array","items":{"type":"string","examples":["jane@acme.com"]}}},"required":["id","to"],"additionalProperties":false},"description":"The variants whose recipients to replace, 1 to 500. The other variants, and the rest of each variant's email settings, stay as they are."}},"required":["variants"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"updated":{"type":"array","items":{"type":"string"},"description":"The variants whose recipients were replaced, by their `id`."},"skipped":{"type":"array","items":{"type":"string"},"description":"The variants passed that were left as they were, by their `id`: those you can't edit, since you only contribute to the burst, and ids that aren't variants of it."}},"required":["updated","skipped"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bursts/{id}/variants/remove":{"post":{"operationId":"removeBurstVariants","summary":"Remove burst variants","description":"Removes variants of a burst by their ids, and deletes their reports. Find the ids with listBurstVariants, which shows each variant's parameter values, and confirm them with the user. The user must be able to edit every variant passed, or nothing is removed: the burst's owner and admins can edit them all, other members only their own.\n\nRequires the `slide_decks:write` scope.","tags":["Bursts"],"x-scope":"slide_decks:write","security":[{"apiKey":[]},{"oauth2":["slide_decks:write"]}],"x-mcp":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The burst to act on, by its `id` from `listBursts`. You can also copy it from the burst's link in Rollstack: it's the part right after `/collections/`.","schema":{"type":"string","description":"The burst to act on, by its `id` from `listBursts`. You can also copy it from the burst's link in Rollstack: it's the part right after `/collections/`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"variantIds":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"string"},"description":"The variants to remove, by their `id` in `listBurstVariants`, which shows each one's parameter values. Each must be a variant of this burst. 1 to 500 ids."}},"required":["variantIds"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"removed":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The removed variant's report id."},"name":{"type":"string","description":"The removed variant's report name."}},"required":["id","name"],"additionalProperties":false},"description":"The variants removed, whose reports are deleted."}},"required":["removed"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/connections":{"get":{"operationId":"listConnections","summary":"List connections","description":"The data source connections the user can see, without their credentials: each one's type, name, settings such as its URL, owner, admins, default user and whether any user's access works.\n\nRequires the `connections:read` scope.","tags":["Connections"],"x-scope":"connections:read","security":[{"apiKey":[]},{"oauth2":["connections:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the connection. Pass it with `type` to the other `/connections/{type}/{id}` endpoints."},"type":{"type":"string","enum":["Tableau","Looker","Metabase","PowerBI","Lightdash","Omni","Sigma","Salesforce","Snowflake","Databricks"],"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`."},"name":{"type":"string","description":"The connection's name, as members see it in Rollstack."},"config":{"type":"object","properties":{"baseUrl":{"description":"The URL of the instance the connection reads from, such as your Looker, Metabase or Snowflake URL. For Sigma, the API base URL of your Sigma organization's region. Power BI and Omni connections have none: an Omni connection's account is in `instanceSlug`.","type":"string"},"siteName":{"description":"Tableau only: the Tableau site the connection reads from, as your Tableau URLs name it after `#/site/`. `null` for a Tableau Server's default site.","anyOf":[{"type":"string"},{"type":"null"}]},"instanceSlug":{"description":"Omni only: your Omni account name, the subdomain of your Omni URL (`acme` in `https://acme.omniapp.co`).","type":"string"},"organizationSlug":{"description":"Sigma only: your Sigma organization, as your Sigma URLs name it after `app.sigmacomputing.com/` (`acme` in `https://app.sigmacomputing.com/acme`).","type":"string"},"projectId":{"description":"Lightdash only: the ID of the Lightdash project whose dashboards the connection reads.","type":"string"},"embeddingMode":{"description":"Looker only: how Rollstack opens the connection's Looker dashboards to capture their charts. `signed`: through embed URLs signed with the connection's embed secret. `private`: through Looker's API, by exporting dashboards as PDFs, which is slower and less reliable. `cookieless` currently works like `signed`.","type":"string","enum":["signed","cookieless","private"]},"authorizationMode":{"description":"Looker and Power BI only: whose permissions in the tool apply when members read data. `per_user`: each member's own, through their own API key in Looker or found by their email in Power BI, if the connection was created with a Power BI email. `impersonated` (Looker only): one admin API key acts as each member's Looker user, found by their email. `shared`: everyone gets the same access, that of the connection's API key in Looker or of the app registration in Power BI.","anyOf":[{"type":"string","enum":["per_user","impersonated","shared"]},{"type":"string","enum":["shared","per_user"]}]},"authMethod":{"description":"Metabase, Snowflake and Databricks only: how Rollstack signs in. For Metabase, `apiKey` uses an admin API key and applies each member's Metabase permissions, found by their email, while `password` signs each member in with their own Metabase password. For Snowflake and Databricks, `oauth` has each member connect their own account through a browser sign-in, while `service` has everyone read through one Snowflake service user, with a key pair, or one Databricks service principal.","anyOf":[{"type":"string","enum":["password","apiKey"]},{"type":"string","enum":["oauth","service"]}]}},"additionalProperties":false,"description":"The connection's settings other than its credentials, which Rollstack never returns. Each type has only the settings that apply to it."},"autoProvision":{"type":"boolean","description":"Whether members who join the organization get access to the connection automatically. When `false`, its owner and admins add members with `addConnectionUsers`."},"isActive":{"type":"boolean","description":"Whether at least one member's access to the connection works, so data can be read through it. `false` when none does: for example, members still have to enter their own credentials in the app, no user in the tool has their email, or their credentials were found invalid."},"defaultUserId":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The user id of the connection's default user, which the app calls its service account. Everyone with access to the connection reads its data through this member's access instead of their own. `null` when there's none, so each member reads with their own access."},"owner":{"anyOf":[{"type":"object","properties":{"id":{"type":"number","description":"The owner's user id, as `listMembers` returns it."},"email":{"type":"string","description":"The owner's email address."}},"required":["id","email"],"additionalProperties":false},{"type":"null"}],"description":"The member who owns the connection, usually the one who created it. Only the owner can delete the connection and add or remove its admins. `null` if no member holds the owner role."},"admins":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"number","description":"The member's user id, as `listMembers` returns it."},"role":{"type":"string","enum":["owner","admin"],"description":"The member's role on the connection. `owner`: owns the connection; only they can delete it and add or remove admins. `admin`: can change the connection's settings and credentials, and manage who has access to it."}},"required":["userId","role"],"additionalProperties":false},"description":"The members who manage the connection, each with their role on it: its owner and its admins."},"hasCredentials":{"type":"boolean","const":true,"description":"Always `true`. Credentials are write-only: Rollstack never returns them. Change them with `replaceConnectionCredentials`."},"createdAt":{"description":"When the connection was created.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the connection was last updated, for example renamed or given new credentials.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","type","name","config","autoProvision","isActive","defaultUserId","owner","admins","hasCredentials","createdAt","updatedAt"],"additionalProperties":false}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createConnection","summary":"Create connection","description":"Creates a data source connection after testing its credentials. Only owners and admins of the organization may. Snowflake and Databricks connect through browser OAuth, so only the app can create them.\n\nRequires the `connections:write` scope.","tags":["Connections"],"x-scope":"connections:write","security":[{"apiKey":[]},{"oauth2":["connections:write"]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","oneOf":[{"type":"object","properties":{"baseUrl":{"description":"The URL of the Tableau Cloud or Server instance the connection reads from. It can't change when replacing credentials: send the connection's current `config.baseUrl`, or create a new connection for another instance. Trailing slashes are removed.","type":"string","examples":["https://acme.online.tableau.com"]},"type":{"type":"string","const":"Tableau","description":"Set to `Tableau` to connect Tableau Cloud or Tableau Server. When replacing credentials, it must match the `type` in the path."},"siteName":{"description":"The Tableau site the connection reads from, as your Tableau URLs name it after `#/site/` (`acme` in `https://online.tableau.com/#/site/acme/workbooks`). `null` for a Tableau Server's default site, which is also what omitting it means when creating the connection. It can't change when replacing credentials: omit it or send the connection's current `config.siteName`.","examples":["acme"],"anyOf":[{"type":"string"},{"type":"null"}]},"clientId":{"type":"string","description":"The Client ID of the Tableau connected app Rollstack signs in through. In Tableau, create it under Settings > Connected Apps > New Connected App > Direct Trust, with access to all projects and all domains allowed, then enable it.","examples":["0f8e1c2d-3b4a-4c5d-9e6f-7a8b9c0d1e2f"]},"secretId":{"type":"string","description":"The Secret ID of the connected app's secret, shown with its Client ID under Settings > Connected Apps in Tableau.","examples":["5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"]},"secretValue":{"type":"string","description":"The Secret Value of the same connected app secret as `secretId`.","examples":["your-connected-app-secret"]},"username":{"type":"string","description":"Your Tableau username, usually your email: the connected app signs in to Tableau as this user, and Rollstack tests the credentials with it. When the connection is created, your access uses it, and each other member who gets access is given a username derived from their Rollstack email in the same pattern, such as their email if this is yours. Members can change theirs in the app.","examples":["jane@acme.com"]},"name":{"type":"string","minLength":1,"description":"The name members will see for the connection in Rollstack.","examples":["Acme Looker"]},"autoProvision":{"default":true,"description":"Whether everyone in the organization gets access to the connection: every active member right away, and each new member as they join. When `false`, only you get access, and you add others with `addConnectionUsers`. Defaults to `true`.","type":"boolean"}},"required":["baseUrl","type","clientId","secretId","secretValue","username","name"],"additionalProperties":false},{"type":"object","properties":{"baseUrl":{"description":"The URL of the Looker instance the connection reads from. It can't change when replacing credentials: send the connection's current `config.baseUrl`, or create a new connection for another instance. Trailing slashes are removed.","type":"string","examples":["https://acme.cloud.looker.com"]},"type":{"type":"string","const":"Looker","description":"Set to `Looker` to connect a Looker instance. When replacing credentials, it must match the `type` in the path."},"clientId":{"type":"string","description":"The client ID of the Looker API key Rollstack connects with. A Looker admin generates it under Admin > Users > Users: open the user or service account, then Edit keys under API keys. With `impersonated` authorization, that Looker user must have the Admin role.","examples":["kG8mQ2xYp4Rz7wNs3Vbc"]},"clientSecret":{"type":"string","description":"The client secret generated with `clientId`, from the same Looker API key.","examples":["your-looker-client-secret"]},"embedSecret":{"type":"string","description":"The embed secret Rollstack signs Looker embed URLs with to open your dashboards. Generate it on the Embed page of Looker's Admin panel, where you also add `https://*.rollstack.com` to the Embedded Domain Allowlist.","examples":["your-looker-embed-secret"]},"embeddingMode":{"type":"string","enum":["signed","cookieless","private"],"description":"How Rollstack opens your Looker dashboards to capture their charts. `signed` (recommended): through embed URLs signed with `embedSecret`. `private`: through Looker's API, by exporting dashboards as PDFs, which is slower and less reliable. `cookieless` currently works like `signed`."},"authorizationMode":{"description":"Whose Looker permissions apply when members read data through the connection. `per_user`: each member reads with an API key of their own Looker user, so they see what their Looker permissions allow; every member needs their own API key set up. `impersonated`: this API key, whose Looker user must have the Admin role, acts as each member's Looker user, found by their email. `shared`: everyone reads with this API key and its permissions. Defaults to `per_user` when creating the connection. Changing it overwrites every member's Looker credentials, which can't be undone. When replacing credentials, omitting it keeps the connection's current value.","type":"string","enum":["per_user","impersonated","shared"]},"lookerUserEmail":{"description":"With `impersonated` authorization, the email of the Looker user this API key acts as when Rollstack tests the credentials, usually your own; the test fails unless this or `lookerUserId` finds a Looker user. When members read data, each acts as the Looker user with their own email instead. When replacing credentials, omitting it keeps the connection's current value.","examples":["jane@acme.com"],"anyOf":[{"type":"string"},{"type":"null"}]},"lookerUserId":{"description":"With `impersonated` authorization, the id of the Looker user this API key acts as when Rollstack tests the credentials. When there's none, Rollstack finds it from `lookerUserEmail`. When replacing credentials, omitting it keeps the connection's current value.","examples":["42"],"anyOf":[{"type":"string"},{"type":"null"}]},"userAttributes":{"description":"Looker user attributes, by attribute name, that Rollstack sets for every member when it opens dashboards through signed embed URLs, such as a `region` your Looker models filter rows by. They take precedence over the Looker user's own values for those attributes. If omitted when creating the connection, none are set. When replacing credentials, omitting it keeps the connection's current value.","examples":[{"region":"EMEA"}],"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"name":{"type":"string","minLength":1,"description":"The name members will see for the connection in Rollstack.","examples":["Acme Looker"]},"autoProvision":{"default":true,"description":"Whether everyone in the organization gets access to the connection: every active member right away, and each new member as they join. When `false`, only you get access, and you add others with `addConnectionUsers`. Defaults to `true`.","type":"boolean"}},"required":["baseUrl","type","clientId","clientSecret","embedSecret","embeddingMode","name"],"additionalProperties":false},{"type":"object","properties":{"baseUrl":{"description":"The URL of the Lightdash instance the connection reads from. It can't change when replacing credentials: send the connection's current `config.baseUrl`, or create a new connection for another instance. Trailing slashes are removed.","type":"string","examples":["https://acme.lightdash.cloud"]},"personalAccessToken":{"type":"string","description":"The Lightdash token Rollstack connects with: a personal access token, starting with `ldpat_`, or a service account token, starting with `ldsvc_`. When the connection is created, your access uses it; every other member sets their own token in the app.","examples":["ldpat_your-personal-access-token"]},"userEmail":{"description":"The email of the Lightdash user whose user attributes Rollstack applies when it opens dashboards through your access. Only used with a service account token (`ldsvc_`); when it's set, the token must have Lightdash's Admin role, or the test fails. If `null`, the attributes of the token's own user apply. When the connection is created, only your access gets it: other members' access applies the attributes of their own token's user. When replacing credentials, omitting it keeps the connection's current value.","examples":["jane@acme.com"],"anyOf":[{"type":"string"},{"type":"null"}]},"projectId":{"type":"string","description":"The ID of the Lightdash project whose dashboards the connection reads, shown at the bottom of the Project Settings page in Lightdash.","examples":["3e5f7a9b-1c2d-4e3f-8a5b-7c9d1e3f5a7b"]},"embedSecret":{"type":"string","description":"The embed secret Rollstack signs Lightdash embed tokens with to open your dashboards. Generate it in Lightdash under Project Settings > Embed Configuration.","examples":["your-lightdash-embed-secret"]},"type":{"type":"string","const":"Lightdash","description":"Set to `Lightdash` to connect a Lightdash project. When replacing credentials, it must match the `type` in the path."},"name":{"type":"string","minLength":1,"description":"The name members will see for the connection in Rollstack.","examples":["Acme Looker"]},"autoProvision":{"default":true,"description":"Whether everyone in the organization gets access to the connection: every active member right away, and each new member as they join. When `false`, only you get access, and you add others with `addConnectionUsers`. Defaults to `true`.","type":"boolean"}},"required":["baseUrl","personalAccessToken","projectId","embedSecret","type","name"],"additionalProperties":false},{"type":"object","properties":{"baseUrl":{"description":"The URL of the Metabase instance the connection reads from. It can't change when replacing credentials: send the connection's current `config.baseUrl`, or create a new connection for another instance. Trailing slashes are removed.","type":"string","examples":["https://acme.metabaseapp.com"]},"embedSecret":{"type":"string","description":"The embedding secret key Rollstack signs Metabase embed URLs with to open your dashboards. In Metabase's Admin settings, go to Embedding, enable embedding, then generate the Embedding Secret Key under More details.","examples":["your-metabase-embedding-secret"]},"authMethod":{"type":"string","enum":["password","apiKey"],"description":"How Rollstack signs in to Metabase. `apiKey` (recommended): with the admin API key in `apiKey`, matching each member to the Metabase user with their email, so they only see the dashboards their Metabase permissions allow. `password`: each member signs in with their own Metabase username and password; members other than you enter their password in the app."},"type":{"type":"string","const":"Metabase","description":"Set to `Metabase` to connect a Metabase instance. When replacing credentials, it must match the `type` in the path."},"username":{"type":"string","description":"Your Metabase username, usually your email. With `password` auth, Rollstack signs in with it and `password`; with `apiKey` auth, it finds your Metabase user, whose permissions apply. When the connection is created, your access uses it, and each other member who gets access is given a username derived from their Rollstack email in the same pattern.","examples":["jane@acme.com"]},"password":{"default":null,"description":"Your Metabase password, required with `password` auth. When the connection is created, only your access gets it: other members enter their own in the app.","examples":["your-metabase-password"],"anyOf":[{"type":"string"},{"type":"null"}]},"apiKey":{"default":null,"description":"The admin API key Rollstack reads Metabase with, required with `apiKey` auth. Every member's access uses it.","examples":["mb_your-api-key"],"anyOf":[{"type":"string"},{"type":"null"}]},"sessionId":{"default":null,"description":"With `password` auth, an existing Metabase session token for Rollstack to use. If omitted, Rollstack signs in with `username` and `password` to get one, and again whenever it stops working.","examples":["8c1d3e5f-7a9b-4c1d-8e3f-5a7b9c1d3e5f"],"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string","minLength":1,"description":"The name members will see for the connection in Rollstack.","examples":["Acme Looker"]},"autoProvision":{"default":true,"description":"Whether everyone in the organization gets access to the connection: every active member right away, and each new member as they join. When `false`, only you get access, and you add others with `addConnectionUsers`. Defaults to `true`.","type":"boolean"}},"required":["baseUrl","embedSecret","authMethod","type","username","name"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Salesforce","description":"Set to `Salesforce` to connect a Salesforce org. When replacing credentials, it must match the `type` in the path."},"baseUrl":{"description":"The URL of the Salesforce instance the connection reads from. It can't change when replacing credentials: send the connection's current `config.baseUrl`, or create a new connection for another instance. Trailing slashes are removed.","type":"string","examples":["https://acme.my.salesforce.com"]},"clientId":{"type":"string","description":"The Consumer Key of the External Client App you create for Rollstack in Salesforce. Enable the JWT Bearer Flow on it and upload Rollstack's certificate, which you can download from the Salesforce connection setup in the Rollstack app. Find the key in the External Client App's Settings tab, under OAuth Settings > Consumer Key and Secret.","examples":["your-consumer-key"]},"username":{"type":"string","description":"Your Salesforce username: Rollstack signs in to Salesforce as this user through the JWT Bearer Flow, and tests the credentials with it. When the connection is created, your access uses it, and each other member who gets access is given a username derived from their Rollstack email in the same pattern.","examples":["jane@acme.com"]},"useCrma":{"type":"boolean","description":"Whether you can also add CRM Analytics dashboards from this connection to Rollstack reports, besides Salesforce reports. When `false`, only Salesforce reports are offered."},"name":{"type":"string","minLength":1,"description":"The name members will see for the connection in Rollstack.","examples":["Acme Looker"]},"autoProvision":{"default":true,"description":"Whether everyone in the organization gets access to the connection: every active member right away, and each new member as they join. When `false`, only you get access, and you add others with `addConnectionUsers`. Defaults to `true`.","type":"boolean"}},"required":["type","baseUrl","clientId","username","useCrma","name"],"additionalProperties":false},{"type":"object","properties":{"clientId":{"type":"string","description":"The Application (client) ID of the Microsoft Entra app registration Rollstack reads Power BI through, shown on its Overview page in the Azure Portal. Add the app to each Power BI workspace Rollstack should read, with the Member role.","examples":["2b4d6f8a-0c1e-4a3b-9d5f-7b9d1f3a5c7e"]},"tenantId":{"type":"string","description":"The Directory (tenant) ID of your Microsoft Entra tenant, shown next to the Application ID on the app registration's Overview page.","examples":["4d6f8a0c-2e3a-4b5c-8d7e-9f1a3b5c7d9e"]},"secretValue":{"type":"string","description":"The Value of a client secret of the app registration, created in the Azure Portal under Certificates & secrets > New client secret.","examples":["your-client-secret-value"]},"userEmail":{"description":"Your email in Power BI, used with `per_user` authorization: your access to the connection then shows only the Power BI reports this account can see, and each other member's access only those their own Power BI account, found by their Rollstack email, can see. If `null` or omitted when creating the connection, no member's Power BI permissions apply, even with `per_user`: everyone sees what the app registration can see. Replacing it later only affects members who get access afterward. When replacing credentials, omitting it keeps the connection's current value.","examples":["jane@acme.com"],"anyOf":[{"type":"string"},{"type":"null"}]},"authorizationMode":{"type":"string","enum":["shared","per_user"],"description":"Whose Power BI permissions apply. `per_user`: each member only sees the Power BI reports their own Power BI account can access, found by their email, as long as `userEmail` is set; the app registration needs read-only Admin API access. `shared`: every member sees everything the app registration can see, whatever their Power BI permissions."},"type":{"type":"string","const":"PowerBI","description":"Set to `PowerBI` to connect Power BI. When replacing credentials, it must match the `type` in the path."},"name":{"type":"string","minLength":1,"description":"The name members will see for the connection in Rollstack.","examples":["Acme Looker"]},"autoProvision":{"default":true,"description":"Whether everyone in the organization gets access to the connection: every active member right away, and each new member as they join. When `false`, only you get access, and you add others with `addConnectionUsers`. Defaults to `true`.","type":"boolean"}},"required":["clientId","tenantId","secretValue","authorizationMode","type","name"],"additionalProperties":false},{"type":"object","properties":{"instanceSlug":{"type":"string","description":"Your Omni account name, the subdomain of your Omni URL (`acme` in `https://acme.omniapp.co`). It can't change when replacing credentials: send the connection's current `config.instanceSlug`.","examples":["acme"]},"externalUserEmail":{"type":"string","description":"The email of your Omni user, usually your own email; the test fails unless an Omni user has it. When the connection is created, your access opens dashboards as this Omni user, with that user's groups, user attributes and dashboards, and each other member's access as the Omni user with their Rollstack email.","examples":["jane@acme.com"]},"apiKey":{"type":"string","description":"An Omni organization API key, which every member's access uses. In Omni, go to Settings > API Access > Organization keys and click Generate New Key.","examples":["your-omni-api-key"]},"embedSecret":{"type":"string","description":"The embed secret Rollstack signs Omni embed URLs with to open your dashboards. In Omni, find it under Settings > Embed > Admin; if there's no Embed section, ask Omni support to enable it.","examples":["your-omni-embed-secret"]},"type":{"type":"string","const":"Omni","description":"Set to `Omni` to connect an Omni account. When replacing credentials, it must match the `type` in the path."},"name":{"type":"string","minLength":1,"description":"The name members will see for the connection in Rollstack.","examples":["Acme Looker"]},"autoProvision":{"default":true,"description":"Whether everyone in the organization gets access to the connection: every active member right away, and each new member as they join. When `false`, only you get access, and you add others with `addConnectionUsers`. Defaults to `true`.","type":"boolean"}},"required":["instanceSlug","externalUserEmail","apiKey","embedSecret","type","name"],"additionalProperties":false},{"type":"object","properties":{"baseUrl":{"type":"string","enum":["https://aws-api.sigmacomputing.com","https://api.us-a.aws.sigmacomputing.com","https://api.ca.aws.sigmacomputing.com","https://api.eu.aws.sigmacomputing.com","https://api.ch.aws.sigmacomputing.com","https://api.uk.aws.sigmacomputing.com","https://api.au.aws.sigmacomputing.com","https://api.in.aws.sigmacomputing.com","https://api.us.azure.sigmacomputing.com","https://api.eu.azure.sigmacomputing.com","https://api.ca.azure.sigmacomputing.com","https://api.uk.azure.sigmacomputing.com","https://api.au.azure.sigmacomputing.com","https://api.sigmacomputing.com","https://api.sa.gcp.sigmacomputing.com"],"description":"The API base URL of your Sigma organization, which depends on the cloud and region it runs in. In Sigma, find it under Administration > Developer access. It can't change when replacing credentials: send the connection's current `config.baseUrl`.","examples":["https://aws-api.sigmacomputing.com"]},"organizationSlug":{"description":"Your Sigma organization, as your Sigma URLs name it after `app.sigmacomputing.com/` (`acme` in `https://app.sigmacomputing.com/acme/workbook/...`). Any Sigma URL of the organization works too. It can't change when replacing credentials: send the connection's current `config.organizationSlug`.","type":"string","examples":["acme"]},"serviceClientId":{"type":"string","minLength":1,"description":"The client ID of Sigma client credentials with the REST API and Embedding scopes, which every member's access uses. Their owner must be an active Sigma Admin. In Sigma, go to Administration > Developer access and click Create new.","examples":["your-sigma-client-id"]},"serviceClientSecret":{"type":"string","minLength":1,"description":"The client secret Sigma shows once, when it creates the client credentials. Rollstack stores it encrypted and never returns it.","examples":["your-sigma-client-secret"]},"externalUserEmail":{"type":"string","description":"The email of your Sigma member, usually your own email; the test fails unless a Sigma member has it. When the connection is created, your access opens workbooks as this Sigma member, and each other member's access as the Sigma member with their Rollstack email.","examples":["jane@acme.com"]},"type":{"type":"string","const":"Sigma","description":"Set to `Sigma` to connect a Sigma organization. When replacing credentials, it must match the `type` in the path."},"name":{"type":"string","minLength":1,"description":"The name members will see for the connection in Rollstack.","examples":["Acme Looker"]},"autoProvision":{"default":true,"description":"Whether everyone in the organization gets access to the connection: every active member right away, and each new member as they join. When `false`, only you get access, and you add others with `addConnectionUsers`. Defaults to `true`.","type":"boolean"}},"required":["baseUrl","organizationSlug","serviceClientId","serviceClientSecret","externalUserEmail","type","name"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["Snowflake","Databricks"],"description":"`Snowflake` or `Databricks`. Create these connections, and change their credentials, in the Rollstack app."}},"required":["type"],"description":"Not supported: Snowflake and Databricks connections are created, and their credentials changed, only in the Rollstack app. A request with either type returns a `400` error."}]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the connection. Pass it with `type` to the other `/connections/{type}/{id}` endpoints."},"type":{"type":"string","enum":["Tableau","Looker","Metabase","PowerBI","Lightdash","Omni","Sigma","Salesforce","Snowflake","Databricks"],"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`."},"name":{"type":"string","description":"The connection's name, as members see it in Rollstack."},"config":{"type":"object","properties":{"baseUrl":{"description":"The URL of the instance the connection reads from, such as your Looker, Metabase or Snowflake URL. For Sigma, the API base URL of your Sigma organization's region. Power BI and Omni connections have none: an Omni connection's account is in `instanceSlug`.","type":"string"},"siteName":{"description":"Tableau only: the Tableau site the connection reads from, as your Tableau URLs name it after `#/site/`. `null` for a Tableau Server's default site.","anyOf":[{"type":"string"},{"type":"null"}]},"instanceSlug":{"description":"Omni only: your Omni account name, the subdomain of your Omni URL (`acme` in `https://acme.omniapp.co`).","type":"string"},"organizationSlug":{"description":"Sigma only: your Sigma organization, as your Sigma URLs name it after `app.sigmacomputing.com/` (`acme` in `https://app.sigmacomputing.com/acme`).","type":"string"},"projectId":{"description":"Lightdash only: the ID of the Lightdash project whose dashboards the connection reads.","type":"string"},"embeddingMode":{"description":"Looker only: how Rollstack opens the connection's Looker dashboards to capture their charts. `signed`: through embed URLs signed with the connection's embed secret. `private`: through Looker's API, by exporting dashboards as PDFs, which is slower and less reliable. `cookieless` currently works like `signed`.","type":"string","enum":["signed","cookieless","private"]},"authorizationMode":{"description":"Looker and Power BI only: whose permissions in the tool apply when members read data. `per_user`: each member's own, through their own API key in Looker or found by their email in Power BI, if the connection was created with a Power BI email. `impersonated` (Looker only): one admin API key acts as each member's Looker user, found by their email. `shared`: everyone gets the same access, that of the connection's API key in Looker or of the app registration in Power BI.","anyOf":[{"type":"string","enum":["per_user","impersonated","shared"]},{"type":"string","enum":["shared","per_user"]}]},"authMethod":{"description":"Metabase, Snowflake and Databricks only: how Rollstack signs in. For Metabase, `apiKey` uses an admin API key and applies each member's Metabase permissions, found by their email, while `password` signs each member in with their own Metabase password. For Snowflake and Databricks, `oauth` has each member connect their own account through a browser sign-in, while `service` has everyone read through one Snowflake service user, with a key pair, or one Databricks service principal.","anyOf":[{"type":"string","enum":["password","apiKey"]},{"type":"string","enum":["oauth","service"]}]}},"additionalProperties":false,"description":"The connection's settings other than its credentials, which Rollstack never returns. Each type has only the settings that apply to it."},"autoProvision":{"type":"boolean","description":"Whether members who join the organization get access to the connection automatically. When `false`, its owner and admins add members with `addConnectionUsers`."},"isActive":{"type":"boolean","description":"Whether at least one member's access to the connection works, so data can be read through it. `false` when none does: for example, members still have to enter their own credentials in the app, no user in the tool has their email, or their credentials were found invalid."},"defaultUserId":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The user id of the connection's default user, which the app calls its service account. Everyone with access to the connection reads its data through this member's access instead of their own. `null` when there's none, so each member reads with their own access."},"owner":{"anyOf":[{"type":"object","properties":{"id":{"type":"number","description":"The owner's user id, as `listMembers` returns it."},"email":{"type":"string","description":"The owner's email address."}},"required":["id","email"],"additionalProperties":false},{"type":"null"}],"description":"The member who owns the connection, usually the one who created it. Only the owner can delete the connection and add or remove its admins. `null` if no member holds the owner role."},"admins":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"number","description":"The member's user id, as `listMembers` returns it."},"role":{"type":"string","enum":["owner","admin"],"description":"The member's role on the connection. `owner`: owns the connection; only they can delete it and add or remove admins. `admin`: can change the connection's settings and credentials, and manage who has access to it."}},"required":["userId","role"],"additionalProperties":false},"description":"The members who manage the connection, each with their role on it: its owner and its admins."},"hasCredentials":{"type":"boolean","const":true,"description":"Always `true`. Credentials are write-only: Rollstack never returns them. Change them with `replaceConnectionCredentials`."},"createdAt":{"description":"When the connection was created.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the connection was last updated, for example renamed or given new credentials.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","type","name","config","autoProvision","isActive","defaultUserId","owner","admins","hasCredentials","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/connections/{type}/{id}":{"get":{"operationId":"getConnection","summary":"Get connection","description":"A data source connection, without its credentials. listConnections gives its type and id.\n\nRequires the `connections:read` scope.","tags":["Connections"],"x-scope":"connections:read","security":[{"apiKey":[]},{"oauth2":["connections:read"]}],"parameters":[{"name":"type","in":"path","required":true,"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`.","schema":{"type":"string","enum":["Tableau","Looker","Metabase","PowerBI","Lightdash","Omni","Sigma","Salesforce","Snowflake","Databricks"],"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`."}},{"name":"id","in":"path","required":true,"description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`.","schema":{"type":"string","description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`."}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the connection. Pass it with `type` to the other `/connections/{type}/{id}` endpoints."},"type":{"type":"string","enum":["Tableau","Looker","Metabase","PowerBI","Lightdash","Omni","Sigma","Salesforce","Snowflake","Databricks"],"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`."},"name":{"type":"string","description":"The connection's name, as members see it in Rollstack."},"config":{"type":"object","properties":{"baseUrl":{"description":"The URL of the instance the connection reads from, such as your Looker, Metabase or Snowflake URL. For Sigma, the API base URL of your Sigma organization's region. Power BI and Omni connections have none: an Omni connection's account is in `instanceSlug`.","type":"string"},"siteName":{"description":"Tableau only: the Tableau site the connection reads from, as your Tableau URLs name it after `#/site/`. `null` for a Tableau Server's default site.","anyOf":[{"type":"string"},{"type":"null"}]},"instanceSlug":{"description":"Omni only: your Omni account name, the subdomain of your Omni URL (`acme` in `https://acme.omniapp.co`).","type":"string"},"organizationSlug":{"description":"Sigma only: your Sigma organization, as your Sigma URLs name it after `app.sigmacomputing.com/` (`acme` in `https://app.sigmacomputing.com/acme`).","type":"string"},"projectId":{"description":"Lightdash only: the ID of the Lightdash project whose dashboards the connection reads.","type":"string"},"embeddingMode":{"description":"Looker only: how Rollstack opens the connection's Looker dashboards to capture their charts. `signed`: through embed URLs signed with the connection's embed secret. `private`: through Looker's API, by exporting dashboards as PDFs, which is slower and less reliable. `cookieless` currently works like `signed`.","type":"string","enum":["signed","cookieless","private"]},"authorizationMode":{"description":"Looker and Power BI only: whose permissions in the tool apply when members read data. `per_user`: each member's own, through their own API key in Looker or found by their email in Power BI, if the connection was created with a Power BI email. `impersonated` (Looker only): one admin API key acts as each member's Looker user, found by their email. `shared`: everyone gets the same access, that of the connection's API key in Looker or of the app registration in Power BI.","anyOf":[{"type":"string","enum":["per_user","impersonated","shared"]},{"type":"string","enum":["shared","per_user"]}]},"authMethod":{"description":"Metabase, Snowflake and Databricks only: how Rollstack signs in. For Metabase, `apiKey` uses an admin API key and applies each member's Metabase permissions, found by their email, while `password` signs each member in with their own Metabase password. For Snowflake and Databricks, `oauth` has each member connect their own account through a browser sign-in, while `service` has everyone read through one Snowflake service user, with a key pair, or one Databricks service principal.","anyOf":[{"type":"string","enum":["password","apiKey"]},{"type":"string","enum":["oauth","service"]}]}},"additionalProperties":false,"description":"The connection's settings other than its credentials, which Rollstack never returns. Each type has only the settings that apply to it."},"autoProvision":{"type":"boolean","description":"Whether members who join the organization get access to the connection automatically. When `false`, its owner and admins add members with `addConnectionUsers`."},"isActive":{"type":"boolean","description":"Whether at least one member's access to the connection works, so data can be read through it. `false` when none does: for example, members still have to enter their own credentials in the app, no user in the tool has their email, or their credentials were found invalid."},"defaultUserId":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The user id of the connection's default user, which the app calls its service account. Everyone with access to the connection reads its data through this member's access instead of their own. `null` when there's none, so each member reads with their own access."},"owner":{"anyOf":[{"type":"object","properties":{"id":{"type":"number","description":"The owner's user id, as `listMembers` returns it."},"email":{"type":"string","description":"The owner's email address."}},"required":["id","email"],"additionalProperties":false},{"type":"null"}],"description":"The member who owns the connection, usually the one who created it. Only the owner can delete the connection and add or remove its admins. `null` if no member holds the owner role."},"admins":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"number","description":"The member's user id, as `listMembers` returns it."},"role":{"type":"string","enum":["owner","admin"],"description":"The member's role on the connection. `owner`: owns the connection; only they can delete it and add or remove admins. `admin`: can change the connection's settings and credentials, and manage who has access to it."}},"required":["userId","role"],"additionalProperties":false},"description":"The members who manage the connection, each with their role on it: its owner and its admins."},"hasCredentials":{"type":"boolean","const":true,"description":"Always `true`. Credentials are write-only: Rollstack never returns them. Change them with `replaceConnectionCredentials`."},"createdAt":{"description":"When the connection was created.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the connection was last updated, for example renamed or given new credentials.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","type","name","config","autoProvision","isActive","defaultUserId","owner","admins","hasCredentials","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateConnection","summary":"Update connection","description":"Renames a connection, changes whether new members get access, or changes the default user, whose access everyone without their own uses. Send only the fields to change, at least one; a null defaultUserId removes the default user.\n\nRequires the `connections:write` scope.","tags":["Connections"],"x-scope":"connections:write","security":[{"apiKey":[]},{"oauth2":["connections:write"]}],"parameters":[{"name":"type","in":"path","required":true,"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`.","schema":{"type":"string","enum":["Tableau","Looker","Metabase","PowerBI","Lightdash","Omni","Sigma","Salesforce","Snowflake","Databricks"],"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`."}},{"name":"id","in":"path","required":true,"description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`.","schema":{"type":"string","description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"description":"The new name members will see for the connection in Rollstack. If omitted, the name stays the same.","examples":["Acme Looker"],"type":"string","minLength":1},"autoProvision":{"description":"Whether members who join the organization from now on get access to the connection automatically. Turning it on doesn't give access to current members who don't have it: add them with `addConnectionUsers`. If omitted, the setting stays the same.","type":"boolean"},"defaultUserId":{"description":"The member to make the connection's default user, which the app calls its service account, by user id from `listConnectionUsers`: they must already have access to the connection. Everyone with access to the connection reads its data through this member's access instead of their own. Setting another member replaces the current default user, and `null` removes it, so each member reads with their own access again. If omitted, it stays the same. Only the connection's owner and admins may change it, and a Databricks connection can't have one. On Sigma, their access must match an active Sigma member, which `isActive` from `listConnectionUsers` shows, or the call answers 404 `datasource-user-not-found`.","examples":[1042],"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}]}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the connection. Pass it with `type` to the other `/connections/{type}/{id}` endpoints."},"type":{"type":"string","enum":["Tableau","Looker","Metabase","PowerBI","Lightdash","Omni","Sigma","Salesforce","Snowflake","Databricks"],"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`."},"name":{"type":"string","description":"The connection's name, as members see it in Rollstack."},"config":{"type":"object","properties":{"baseUrl":{"description":"The URL of the instance the connection reads from, such as your Looker, Metabase or Snowflake URL. For Sigma, the API base URL of your Sigma organization's region. Power BI and Omni connections have none: an Omni connection's account is in `instanceSlug`.","type":"string"},"siteName":{"description":"Tableau only: the Tableau site the connection reads from, as your Tableau URLs name it after `#/site/`. `null` for a Tableau Server's default site.","anyOf":[{"type":"string"},{"type":"null"}]},"instanceSlug":{"description":"Omni only: your Omni account name, the subdomain of your Omni URL (`acme` in `https://acme.omniapp.co`).","type":"string"},"organizationSlug":{"description":"Sigma only: your Sigma organization, as your Sigma URLs name it after `app.sigmacomputing.com/` (`acme` in `https://app.sigmacomputing.com/acme`).","type":"string"},"projectId":{"description":"Lightdash only: the ID of the Lightdash project whose dashboards the connection reads.","type":"string"},"embeddingMode":{"description":"Looker only: how Rollstack opens the connection's Looker dashboards to capture their charts. `signed`: through embed URLs signed with the connection's embed secret. `private`: through Looker's API, by exporting dashboards as PDFs, which is slower and less reliable. `cookieless` currently works like `signed`.","type":"string","enum":["signed","cookieless","private"]},"authorizationMode":{"description":"Looker and Power BI only: whose permissions in the tool apply when members read data. `per_user`: each member's own, through their own API key in Looker or found by their email in Power BI, if the connection was created with a Power BI email. `impersonated` (Looker only): one admin API key acts as each member's Looker user, found by their email. `shared`: everyone gets the same access, that of the connection's API key in Looker or of the app registration in Power BI.","anyOf":[{"type":"string","enum":["per_user","impersonated","shared"]},{"type":"string","enum":["shared","per_user"]}]},"authMethod":{"description":"Metabase, Snowflake and Databricks only: how Rollstack signs in. For Metabase, `apiKey` uses an admin API key and applies each member's Metabase permissions, found by their email, while `password` signs each member in with their own Metabase password. For Snowflake and Databricks, `oauth` has each member connect their own account through a browser sign-in, while `service` has everyone read through one Snowflake service user, with a key pair, or one Databricks service principal.","anyOf":[{"type":"string","enum":["password","apiKey"]},{"type":"string","enum":["oauth","service"]}]}},"additionalProperties":false,"description":"The connection's settings other than its credentials, which Rollstack never returns. Each type has only the settings that apply to it."},"autoProvision":{"type":"boolean","description":"Whether members who join the organization get access to the connection automatically. When `false`, its owner and admins add members with `addConnectionUsers`."},"isActive":{"type":"boolean","description":"Whether at least one member's access to the connection works, so data can be read through it. `false` when none does: for example, members still have to enter their own credentials in the app, no user in the tool has their email, or their credentials were found invalid."},"defaultUserId":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The user id of the connection's default user, which the app calls its service account. Everyone with access to the connection reads its data through this member's access instead of their own. `null` when there's none, so each member reads with their own access."},"owner":{"anyOf":[{"type":"object","properties":{"id":{"type":"number","description":"The owner's user id, as `listMembers` returns it."},"email":{"type":"string","description":"The owner's email address."}},"required":["id","email"],"additionalProperties":false},{"type":"null"}],"description":"The member who owns the connection, usually the one who created it. Only the owner can delete the connection and add or remove its admins. `null` if no member holds the owner role."},"admins":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"number","description":"The member's user id, as `listMembers` returns it."},"role":{"type":"string","enum":["owner","admin"],"description":"The member's role on the connection. `owner`: owns the connection; only they can delete it and add or remove admins. `admin`: can change the connection's settings and credentials, and manage who has access to it."}},"required":["userId","role"],"additionalProperties":false},"description":"The members who manage the connection, each with their role on it: its owner and its admins."},"hasCredentials":{"type":"boolean","const":true,"description":"Always `true`. Credentials are write-only: Rollstack never returns them. Change them with `replaceConnectionCredentials`."},"createdAt":{"description":"When the connection was created.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"description":"When the connection was last updated, for example renamed or given new credentials.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","type","name","config","autoProvision","isActive","defaultUserId","owner","admins","hasCredentials","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteConnection","summary":"Delete connection","description":"Deletes a connection with every user's access to it and every sync that uses it. Only its owner may.\n\nRequires the `connections:write` scope.","tags":["Connections"],"x-scope":"connections:write","security":[{"apiKey":[]},{"oauth2":["connections:write"]}],"parameters":[{"name":"type","in":"path","required":true,"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`.","schema":{"type":"string","enum":["Tableau","Looker","Metabase","PowerBI","Lightdash","Omni","Sigma","Salesforce","Snowflake","Databricks"],"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`."}},{"name":"id","in":"path","required":true,"description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`.","schema":{"type":"string","description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`."}}],"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/connections/{type}/{id}/dashboards":{"get":{"operationId":"searchDashboards","summary":"Search dashboards","description":"The dashboards of a Looker, Metabase, Omni, Lightdash, Sigma, Tableau or Power BI connection whose name holds any word of query or its singular, in any case, at most 50: those the most of the organization's reports read first, copies, old and personal ones last, then most words first, read with the user's access to the connection. A Tableau dashboard is a workbook, its views its tabs; a Power BI one a report, its pages its tabs; a Sigma one a workbook, its pages its tabs. On a Sigma connection, query can be a link to a workbook the user pasted: it finds only that workbook, with the page the link opens on as tabId, but not the link's control values, saved view or tag, and a link to another Sigma organization is rejected. Search by the name the user gives, confirm the dashboard with the user, then check its tabs and charts with getDashboard or add it to a report with addReportDatasheets. listConnections gives the connection's type and id.\n\nRequires the `connections:read` scope.","tags":["Connections"],"x-scope":"connections:read","security":[{"apiKey":[]},{"oauth2":["connections:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"type","in":"path","required":true,"description":"The type of connection, as `type` in `listConnections`: the BI tool it connects to. Only Looker, Metabase, Omni, Lightdash, Sigma, Tableau and Power BI (`PowerBI`) connections have dashboards.","schema":{"type":"string","enum":["Looker","Metabase","Omni","Lightdash","Tableau","PowerBI","Sigma"],"description":"The type of connection, as `type` in `listConnections`: the BI tool it connects to. Only Looker, Metabase, Omni, Lightdash, Sigma, Tableau and Power BI (`PowerBI`) connections have dashboards."}},{"name":"id","in":"path","required":true,"description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`.","schema":{"type":"string","description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`."}},{"name":"query","in":"query","required":false,"description":"Words to search for in names, separated by spaces: a dashboard or spreadsheet is returned when its name contains any of them, case-insensitively. If omitted, results aren't filtered by name. At most 50 results are returned either way.","schema":{"description":"Words to search for in names, separated by spaces: a dashboard or spreadsheet is returned when its name contains any of them, case-insensitively. If omitted, results aren't filtered by name. At most 50 results are returned either way.","examples":["revenue"],"type":"string","minLength":1}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Identifies the dashboard in its BI tool. Pass it as `dashboardId` to `getDashboard` or `addReportDatasheets`. For Tableau it is the workbook's id; for Power BI, the report's workspace id and report id, joined by a dot; for Sigma, the workbook's UUID, not the short id in its links."},"name":{"type":"string","description":"The dashboard's name in its BI tool. For Tableau and Sigma it is the workbook's name, for Power BI the report's."},"folder":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Where the dashboard is filed in its BI tool: its Looker or Omni folder, Metabase collection, Power BI workspace or Sigma path (`My Documents` for a workbook in your own Sigma documents). Helps tell apart dashboards with the same name, such as copies of a Power BI report in several workspaces. `null` when the BI tool gives none, and always for Lightdash and Tableau."},"decks":{"type":"number","description":"How many of your organization's reports have a datasheet that reads from this dashboard through this connection. Results are sorted by this count, highest first."},"tabId":{"description":"Only for a Sigma workbook found by a link to one of its pages or elements: the page the link opens on, to pass as `tabId` to `getDashboard` or `addReportDatasheets`.","type":"string"},"tabName":{"description":"Only with `tabId`: the name of the page the link opens on, as Sigma shows it.","type":"string"}},"required":["id","name","folder","decks"],"additionalProperties":false}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/connections/{type}/{id}/dashboards/{dashboardId}":{"get":{"operationId":"getDashboard","summary":"Get dashboard","description":"A dashboard of a Looker, Metabase, Omni, Lightdash, Sigma, Tableau or Power BI connection, read with the user's access to the connection: its tabs, and the charts and filters of the tab tabId names, one of the ids in tabs (else the one the dashboard opens on, a Power BI report's or Sigma workbook's first page). Tableau and Power BI list no charts or filters, which only the app reads; a Sigma page lists its charts and tables, and the workbook's controls as its filters. Find the dashboard's id with searchDashboards. Confirm the dashboard and tab with the user, then add it to a report with addReportDatasheets; for another tab, call it again with that tab's id from tabs.\n\nRequires the `connections:read` scope.","tags":["Connections"],"x-scope":"connections:read","security":[{"apiKey":[]},{"oauth2":["connections:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"type","in":"path","required":true,"description":"The type of connection, as `type` in `listConnections`: the BI tool it connects to. Only Looker, Metabase, Omni, Lightdash, Sigma, Tableau and Power BI (`PowerBI`) connections have dashboards.","schema":{"type":"string","enum":["Looker","Metabase","Omni","Lightdash","Tableau","PowerBI","Sigma"],"description":"The type of connection, as `type` in `listConnections`: the BI tool it connects to. Only Looker, Metabase, Omni, Lightdash, Sigma, Tableau and Power BI (`PowerBI`) connections have dashboards."}},{"name":"id","in":"path","required":true,"description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`.","schema":{"type":"string","description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`."}},{"name":"dashboardId","in":"path","required":true,"description":"The dashboard to read, by the `id` that `searchDashboards` returns.","schema":{"type":"string","description":"The dashboard to read, by the `id` that `searchDashboards` returns."}},{"name":"tabId","in":"query","required":false,"description":"The dashboard tab to read, by its `id` from the `tabs` that `getDashboard` returns: a Looker, Metabase or Lightdash tab, a Tableau view, a Power BI page or a Sigma page. If omitted, the dashboard's first tab is used, or the whole dashboard when it has no tabs, as on Omni. A tab the dashboard doesn't have returns a 404 error.","schema":{"description":"The dashboard tab to read, by its `id` from the `tabs` that `getDashboard` returns: a Looker, Metabase or Lightdash tab, a Tableau view, a Power BI page or a Sigma page. If omitted, the dashboard's first tab is used, or the whole dashboard when it has no tabs, as on Omni. A tab the dashboard doesn't have returns a 404 error.","examples":["12-overview"],"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"connection":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the connection, the `id` in the request path."},"type":{"type":"string","enum":["Tableau","Looker","Metabase","PowerBI","Lightdash","Omni","Sigma","Salesforce","Snowflake","Databricks"],"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`."},"name":{"type":"string","description":"The connection's name, as members see it in Rollstack."}},"required":["id","type","name"],"additionalProperties":false,"description":"The connection the dashboard was read through: the one in the request path."},"dashboard":{"type":"object","properties":{"id":{"type":"string","description":"Identifies the dashboard in its BI tool. Pass it as `dashboardId` to `getDashboard` or `addReportDatasheets`. For Tableau it is the workbook's id; for Power BI, the report's workspace id and report id, joined by a dot; for Sigma, the workbook's UUID, not the short id in its links."},"name":{"type":"string","description":"The dashboard's name in its BI tool. For Tableau and Sigma it is the workbook's name, for Power BI the report's."},"url":{"type":"string","description":"A link that opens the dashboard in its BI tool. For Tableau, it opens the workbook on the view in `tabId`; for Sigma, on its first page."}},"required":["id","name","url"],"additionalProperties":false,"description":"The dashboard you asked for."},"tabs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Identifies the tab. Pass it as `tabId` to read that tab with `getDashboard`, or to add it to a report with `addReportDatasheets`. Its form depends on the BI tool: a Looker layout id, a Metabase `{id}-{slug}` such as `12-overview`, a Lightdash tab uuid, a Tableau view id, a Power BI page's internal name or a Sigma page id."},"name":{"type":"string","description":"The tab's name as shown in the BI tool, such as a Power BI page's display name."}},"required":["id","name"],"additionalProperties":false},"description":"The dashboard's tabs: a Looker, Metabase or Lightdash dashboard's tabs, a Tableau workbook's views, a Power BI report's pages or a Sigma workbook's pages, never its hidden ones. Empty when the dashboard has no tabs, as always on Omni."},"tabId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The tab `elements` comes from: the one you passed as `tabId`, or the dashboard's first tab if you passed none. `null` when the dashboard was read as a whole, as when it has no tabs."},"elements":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Identifies the element in its BI tool, such as a Looker tile's id, a Metabase dashboard card's id, a Lightdash chart's uuid or a Sigma element's id."},"name":{"type":"string","description":"The element's title as shown on the dashboard. An element without a title, such as a text card, is named after its type instead, as in `Text`."},"type":{"type":"string","description":"The kind of element, in the BI tool's own terms, such as `looker_column` for a Looker column chart, `saved_chart` for a Lightdash chart, `kpi-chart` for a Sigma KPI or `text` for a Metabase text card."}},"required":["id","name","type"],"additionalProperties":false},"description":"The charts and other elements on that tab, or on the whole dashboard when `tabId` is `null`. Once you add the tab to a report with `addReportDatasheets`, the slides agent can add these elements to the report's slides. For Sigma, only the page's charts and tables, without its texts, images and controls. Always empty for Tableau and Power BI, whose charts only the app can list."},"filters":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"The filter's label as shown on the dashboard. For Metabase it is the filter's slug instead, and for a Sigma control without a label, its control ID."}},"required":["name"],"additionalProperties":false},"description":"The dashboard's filters, and on Omni its controls too. For Sigma, the controls on every page of the workbook, so two can share a label. Always empty for Tableau and Power BI."}},"required":["connection","dashboard","tabs","tabId","elements","filters"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/connections/{type}/{id}/credentials":{"put":{"operationId":"replaceConnectionCredentials","summary":"Replace credentials","description":"Replaces every credential of a connection, after testing them. Its users' access gets the new credentials too. The instance (baseUrl, siteName, instanceSlug, organizationSlug) can't change; siteName can be left out to keep the stored site. Settings the connection doesn't show (Looker user and attributes, userEmail) keep their value when left out, but Omni's and Sigma's externalUserEmail must be sent. A failed test answers 422 with the provider's code and message.\n\nRequires the `credentials:write` scope.","tags":["Connections"],"x-scope":"credentials:write","security":[{"apiKey":[]},{"oauth2":["credentials:write"]}],"parameters":[{"name":"type","in":"path","required":true,"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`.","schema":{"type":"string","enum":["Tableau","Looker","Metabase","PowerBI","Lightdash","Omni","Sigma","Salesforce","Snowflake","Databricks"],"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`."}},{"name":"id","in":"path","required":true,"description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`.","schema":{"type":"string","description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","oneOf":[{"type":"object","properties":{"baseUrl":{"description":"The URL of the Tableau Cloud or Server instance the connection reads from. It can't change when replacing credentials: send the connection's current `config.baseUrl`, or create a new connection for another instance. Trailing slashes are removed.","type":"string","examples":["https://acme.online.tableau.com"]},"type":{"type":"string","const":"Tableau","description":"Set to `Tableau` to connect Tableau Cloud or Tableau Server. When replacing credentials, it must match the `type` in the path."},"siteName":{"description":"The Tableau site the connection reads from, as your Tableau URLs name it after `#/site/` (`acme` in `https://online.tableau.com/#/site/acme/workbooks`). `null` for a Tableau Server's default site, which is also what omitting it means when creating the connection. It can't change when replacing credentials: omit it or send the connection's current `config.siteName`.","examples":["acme"],"anyOf":[{"type":"string"},{"type":"null"}]},"clientId":{"type":"string","description":"The Client ID of the Tableau connected app Rollstack signs in through. In Tableau, create it under Settings > Connected Apps > New Connected App > Direct Trust, with access to all projects and all domains allowed, then enable it.","examples":["0f8e1c2d-3b4a-4c5d-9e6f-7a8b9c0d1e2f"]},"secretId":{"type":"string","description":"The Secret ID of the connected app's secret, shown with its Client ID under Settings > Connected Apps in Tableau.","examples":["5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"]},"secretValue":{"type":"string","description":"The Secret Value of the same connected app secret as `secretId`.","examples":["your-connected-app-secret"]},"username":{"type":"string","description":"Your Tableau username, usually your email: the connected app signs in to Tableau as this user, and Rollstack tests the credentials with it. When the connection is created, your access uses it, and each other member who gets access is given a username derived from their Rollstack email in the same pattern, such as their email if this is yours. Members can change theirs in the app.","examples":["jane@acme.com"]}},"required":["baseUrl","type","clientId","secretId","secretValue","username"],"additionalProperties":false},{"type":"object","properties":{"baseUrl":{"description":"The URL of the Looker instance the connection reads from. It can't change when replacing credentials: send the connection's current `config.baseUrl`, or create a new connection for another instance. Trailing slashes are removed.","type":"string","examples":["https://acme.cloud.looker.com"]},"type":{"type":"string","const":"Looker","description":"Set to `Looker` to connect a Looker instance. When replacing credentials, it must match the `type` in the path."},"clientId":{"type":"string","description":"The client ID of the Looker API key Rollstack connects with. A Looker admin generates it under Admin > Users > Users: open the user or service account, then Edit keys under API keys. With `impersonated` authorization, that Looker user must have the Admin role.","examples":["kG8mQ2xYp4Rz7wNs3Vbc"]},"clientSecret":{"type":"string","description":"The client secret generated with `clientId`, from the same Looker API key.","examples":["your-looker-client-secret"]},"embedSecret":{"type":"string","description":"The embed secret Rollstack signs Looker embed URLs with to open your dashboards. Generate it on the Embed page of Looker's Admin panel, where you also add `https://*.rollstack.com` to the Embedded Domain Allowlist.","examples":["your-looker-embed-secret"]},"embeddingMode":{"type":"string","enum":["signed","cookieless","private"],"description":"How Rollstack opens your Looker dashboards to capture their charts. `signed` (recommended): through embed URLs signed with `embedSecret`. `private`: through Looker's API, by exporting dashboards as PDFs, which is slower and less reliable. `cookieless` currently works like `signed`."},"authorizationMode":{"description":"Whose Looker permissions apply when members read data through the connection. `per_user`: each member reads with an API key of their own Looker user, so they see what their Looker permissions allow; every member needs their own API key set up. `impersonated`: this API key, whose Looker user must have the Admin role, acts as each member's Looker user, found by their email. `shared`: everyone reads with this API key and its permissions. Defaults to `per_user` when creating the connection. Changing it overwrites every member's Looker credentials, which can't be undone. When replacing credentials, omitting it keeps the connection's current value.","type":"string","enum":["per_user","impersonated","shared"]},"lookerUserEmail":{"description":"With `impersonated` authorization, the email of the Looker user this API key acts as when Rollstack tests the credentials, usually your own; the test fails unless this or `lookerUserId` finds a Looker user. When members read data, each acts as the Looker user with their own email instead. When replacing credentials, omitting it keeps the connection's current value.","examples":["jane@acme.com"],"anyOf":[{"type":"string"},{"type":"null"}]},"lookerUserId":{"description":"With `impersonated` authorization, the id of the Looker user this API key acts as when Rollstack tests the credentials. When there's none, Rollstack finds it from `lookerUserEmail`. When replacing credentials, omitting it keeps the connection's current value.","examples":["42"],"anyOf":[{"type":"string"},{"type":"null"}]},"userAttributes":{"description":"Looker user attributes, by attribute name, that Rollstack sets for every member when it opens dashboards through signed embed URLs, such as a `region` your Looker models filter rows by. They take precedence over the Looker user's own values for those attributes. If omitted when creating the connection, none are set. When replacing credentials, omitting it keeps the connection's current value.","examples":[{"region":"EMEA"}],"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"required":["baseUrl","type","clientId","clientSecret","embedSecret","embeddingMode"],"additionalProperties":false},{"type":"object","properties":{"baseUrl":{"description":"The URL of the Lightdash instance the connection reads from. It can't change when replacing credentials: send the connection's current `config.baseUrl`, or create a new connection for another instance. Trailing slashes are removed.","type":"string","examples":["https://acme.lightdash.cloud"]},"personalAccessToken":{"type":"string","description":"The Lightdash token Rollstack connects with: a personal access token, starting with `ldpat_`, or a service account token, starting with `ldsvc_`. When the connection is created, your access uses it; every other member sets their own token in the app.","examples":["ldpat_your-personal-access-token"]},"userEmail":{"description":"The email of the Lightdash user whose user attributes Rollstack applies when it opens dashboards through your access. Only used with a service account token (`ldsvc_`); when it's set, the token must have Lightdash's Admin role, or the test fails. If `null`, the attributes of the token's own user apply. When the connection is created, only your access gets it: other members' access applies the attributes of their own token's user. When replacing credentials, omitting it keeps the connection's current value.","examples":["jane@acme.com"],"anyOf":[{"type":"string"},{"type":"null"}]},"projectId":{"type":"string","description":"The ID of the Lightdash project whose dashboards the connection reads, shown at the bottom of the Project Settings page in Lightdash.","examples":["3e5f7a9b-1c2d-4e3f-8a5b-7c9d1e3f5a7b"]},"embedSecret":{"type":"string","description":"The embed secret Rollstack signs Lightdash embed tokens with to open your dashboards. Generate it in Lightdash under Project Settings > Embed Configuration.","examples":["your-lightdash-embed-secret"]},"type":{"type":"string","const":"Lightdash","description":"Set to `Lightdash` to connect a Lightdash project. When replacing credentials, it must match the `type` in the path."}},"required":["baseUrl","personalAccessToken","projectId","embedSecret","type"],"additionalProperties":false},{"type":"object","properties":{"baseUrl":{"description":"The URL of the Metabase instance the connection reads from. It can't change when replacing credentials: send the connection's current `config.baseUrl`, or create a new connection for another instance. Trailing slashes are removed.","type":"string","examples":["https://acme.metabaseapp.com"]},"embedSecret":{"type":"string","description":"The embedding secret key Rollstack signs Metabase embed URLs with to open your dashboards. In Metabase's Admin settings, go to Embedding, enable embedding, then generate the Embedding Secret Key under More details.","examples":["your-metabase-embedding-secret"]},"authMethod":{"type":"string","enum":["password","apiKey"],"description":"How Rollstack signs in to Metabase. `apiKey` (recommended): with the admin API key in `apiKey`, matching each member to the Metabase user with their email, so they only see the dashboards their Metabase permissions allow. `password`: each member signs in with their own Metabase username and password; members other than you enter their password in the app."},"type":{"type":"string","const":"Metabase","description":"Set to `Metabase` to connect a Metabase instance. When replacing credentials, it must match the `type` in the path."},"username":{"type":"string","description":"Your Metabase username, usually your email. With `password` auth, Rollstack signs in with it and `password`; with `apiKey` auth, it finds your Metabase user, whose permissions apply. When the connection is created, your access uses it, and each other member who gets access is given a username derived from their Rollstack email in the same pattern.","examples":["jane@acme.com"]},"password":{"default":null,"description":"Your Metabase password, required with `password` auth. When the connection is created, only your access gets it: other members enter their own in the app.","examples":["your-metabase-password"],"anyOf":[{"type":"string"},{"type":"null"}]},"apiKey":{"default":null,"description":"The admin API key Rollstack reads Metabase with, required with `apiKey` auth. Every member's access uses it.","examples":["mb_your-api-key"],"anyOf":[{"type":"string"},{"type":"null"}]},"sessionId":{"default":null,"description":"With `password` auth, an existing Metabase session token for Rollstack to use. If omitted, Rollstack signs in with `username` and `password` to get one, and again whenever it stops working.","examples":["8c1d3e5f-7a9b-4c1d-8e3f-5a7b9c1d3e5f"],"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["baseUrl","embedSecret","authMethod","type","username"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Salesforce","description":"Set to `Salesforce` to connect a Salesforce org. When replacing credentials, it must match the `type` in the path."},"baseUrl":{"description":"The URL of the Salesforce instance the connection reads from. It can't change when replacing credentials: send the connection's current `config.baseUrl`, or create a new connection for another instance. Trailing slashes are removed.","type":"string","examples":["https://acme.my.salesforce.com"]},"clientId":{"type":"string","description":"The Consumer Key of the External Client App you create for Rollstack in Salesforce. Enable the JWT Bearer Flow on it and upload Rollstack's certificate, which you can download from the Salesforce connection setup in the Rollstack app. Find the key in the External Client App's Settings tab, under OAuth Settings > Consumer Key and Secret.","examples":["your-consumer-key"]},"username":{"type":"string","description":"Your Salesforce username: Rollstack signs in to Salesforce as this user through the JWT Bearer Flow, and tests the credentials with it. When the connection is created, your access uses it, and each other member who gets access is given a username derived from their Rollstack email in the same pattern.","examples":["jane@acme.com"]},"useCrma":{"type":"boolean","description":"Whether you can also add CRM Analytics dashboards from this connection to Rollstack reports, besides Salesforce reports. When `false`, only Salesforce reports are offered."}},"required":["type","baseUrl","clientId","username","useCrma"],"additionalProperties":false},{"type":"object","properties":{"clientId":{"type":"string","description":"The Application (client) ID of the Microsoft Entra app registration Rollstack reads Power BI through, shown on its Overview page in the Azure Portal. Add the app to each Power BI workspace Rollstack should read, with the Member role.","examples":["2b4d6f8a-0c1e-4a3b-9d5f-7b9d1f3a5c7e"]},"tenantId":{"type":"string","description":"The Directory (tenant) ID of your Microsoft Entra tenant, shown next to the Application ID on the app registration's Overview page.","examples":["4d6f8a0c-2e3a-4b5c-8d7e-9f1a3b5c7d9e"]},"secretValue":{"type":"string","description":"The Value of a client secret of the app registration, created in the Azure Portal under Certificates & secrets > New client secret.","examples":["your-client-secret-value"]},"userEmail":{"description":"Your email in Power BI, used with `per_user` authorization: your access to the connection then shows only the Power BI reports this account can see, and each other member's access only those their own Power BI account, found by their Rollstack email, can see. If `null` or omitted when creating the connection, no member's Power BI permissions apply, even with `per_user`: everyone sees what the app registration can see. Replacing it later only affects members who get access afterward. When replacing credentials, omitting it keeps the connection's current value.","examples":["jane@acme.com"],"anyOf":[{"type":"string"},{"type":"null"}]},"authorizationMode":{"type":"string","enum":["shared","per_user"],"description":"Whose Power BI permissions apply. `per_user`: each member only sees the Power BI reports their own Power BI account can access, found by their email, as long as `userEmail` is set; the app registration needs read-only Admin API access. `shared`: every member sees everything the app registration can see, whatever their Power BI permissions."},"type":{"type":"string","const":"PowerBI","description":"Set to `PowerBI` to connect Power BI. When replacing credentials, it must match the `type` in the path."}},"required":["clientId","tenantId","secretValue","authorizationMode","type"],"additionalProperties":false},{"type":"object","properties":{"instanceSlug":{"type":"string","description":"Your Omni account name, the subdomain of your Omni URL (`acme` in `https://acme.omniapp.co`). It can't change when replacing credentials: send the connection's current `config.instanceSlug`.","examples":["acme"]},"externalUserEmail":{"type":"string","description":"The email of your Omni user, usually your own email; the test fails unless an Omni user has it. When the connection is created, your access opens dashboards as this Omni user, with that user's groups, user attributes and dashboards, and each other member's access as the Omni user with their Rollstack email.","examples":["jane@acme.com"]},"apiKey":{"type":"string","description":"An Omni organization API key, which every member's access uses. In Omni, go to Settings > API Access > Organization keys and click Generate New Key.","examples":["your-omni-api-key"]},"embedSecret":{"type":"string","description":"The embed secret Rollstack signs Omni embed URLs with to open your dashboards. In Omni, find it under Settings > Embed > Admin; if there's no Embed section, ask Omni support to enable it.","examples":["your-omni-embed-secret"]},"type":{"type":"string","const":"Omni","description":"Set to `Omni` to connect an Omni account. When replacing credentials, it must match the `type` in the path."}},"required":["instanceSlug","externalUserEmail","apiKey","embedSecret","type"],"additionalProperties":false},{"type":"object","properties":{"baseUrl":{"type":"string","enum":["https://aws-api.sigmacomputing.com","https://api.us-a.aws.sigmacomputing.com","https://api.ca.aws.sigmacomputing.com","https://api.eu.aws.sigmacomputing.com","https://api.ch.aws.sigmacomputing.com","https://api.uk.aws.sigmacomputing.com","https://api.au.aws.sigmacomputing.com","https://api.in.aws.sigmacomputing.com","https://api.us.azure.sigmacomputing.com","https://api.eu.azure.sigmacomputing.com","https://api.ca.azure.sigmacomputing.com","https://api.uk.azure.sigmacomputing.com","https://api.au.azure.sigmacomputing.com","https://api.sigmacomputing.com","https://api.sa.gcp.sigmacomputing.com"],"description":"The API base URL of your Sigma organization, which depends on the cloud and region it runs in. In Sigma, find it under Administration > Developer access. It can't change when replacing credentials: send the connection's current `config.baseUrl`.","examples":["https://aws-api.sigmacomputing.com"]},"organizationSlug":{"description":"Your Sigma organization, as your Sigma URLs name it after `app.sigmacomputing.com/` (`acme` in `https://app.sigmacomputing.com/acme/workbook/...`). Any Sigma URL of the organization works too. It can't change when replacing credentials: send the connection's current `config.organizationSlug`.","type":"string","examples":["acme"]},"serviceClientId":{"type":"string","minLength":1,"description":"The client ID of Sigma client credentials with the REST API and Embedding scopes, which every member's access uses. Their owner must be an active Sigma Admin. In Sigma, go to Administration > Developer access and click Create new.","examples":["your-sigma-client-id"]},"serviceClientSecret":{"type":"string","minLength":1,"description":"The client secret Sigma shows once, when it creates the client credentials. Rollstack stores it encrypted and never returns it.","examples":["your-sigma-client-secret"]},"externalUserEmail":{"type":"string","description":"The email of your Sigma member, usually your own email; the test fails unless a Sigma member has it. When the connection is created, your access opens workbooks as this Sigma member, and each other member's access as the Sigma member with their Rollstack email.","examples":["jane@acme.com"]},"type":{"type":"string","const":"Sigma","description":"Set to `Sigma` to connect a Sigma organization. When replacing credentials, it must match the `type` in the path."}},"required":["baseUrl","organizationSlug","serviceClientId","serviceClientSecret","externalUserEmail","type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["Snowflake","Databricks"],"description":"`Snowflake` or `Databricks`. Create these connections, and change their credentials, in the Rollstack app."}},"required":["type"],"description":"Not supported: Snowflake and Databricks connections are created, and their credentials changed, only in the Rollstack app. A request with either type returns a `400` error."}]}}}},"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/connections/{type}/{id}/users":{"get":{"operationId":"listConnectionUsers","summary":"List connection users","description":"The users with access to a connection, with whether each is the default user and whether their access works. Only its admins may.\n\nRequires the `connections:read` scope.","tags":["Connection users"],"x-scope":"connections:read","security":[{"apiKey":[]},{"oauth2":["connections:read"]}],"parameters":[{"name":"type","in":"path","required":true,"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`.","schema":{"type":"string","enum":["Tableau","Looker","Metabase","PowerBI","Lightdash","Omni","Sigma","Salesforce","Snowflake","Databricks"],"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`."}},{"name":"id","in":"path","required":true,"description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`.","schema":{"type":"string","description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`."}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"array","items":{"type":"object","properties":{"userId":{"type":"number","description":"Identifies the user, as their `id` in `listMembers`. Pass it as `userId` to `removeConnectionUser`, or as `defaultUserId` to `updateConnection` to make them the default user."},"email":{"type":"string","description":"The email address of the user's Rollstack account."},"isDefault":{"type":"boolean","description":"Whether this user is the connection's default user, called its service account in the app. While a connection has a default user, Rollstack reads data through the default user's access for everyone with access to the connection, instead of through their own. A connection has at most one, set with `defaultUserId` in `updateConnection`; Databricks connections can't have one."},"isActive":{"type":"boolean","description":"Whether the user's access to the connection is set up and working, shown as Active or Inactive in the connection's list of users in the app. It is `false`, for example, until a Lightdash user enters their personal access token in the app, or when Rollstack couldn't connect to Tableau as that user. It is also `false` while their access is suspended."}},"required":["userId","email","isDefault","isActive"],"additionalProperties":false}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"addConnectionUsers","summary":"Add connection users","description":"Gives members of the organization access to a connection. Only its admins may. Answers the users who got access; others are skipped.\n\nRequires the `connections:write` scope.","tags":["Connection users"],"x-scope":"connections:write","security":[{"apiKey":[]},{"oauth2":["connections:write"]}],"parameters":[{"name":"type","in":"path","required":true,"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`.","schema":{"type":"string","enum":["Tableau","Looker","Metabase","PowerBI","Lightdash","Omni","Sigma","Salesforce","Snowflake","Databricks"],"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`."}},{"name":"id","in":"path","required":true,"description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`.","schema":{"type":"string","description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"userIds":{"minItems":1,"maxItems":100,"type":"array","items":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"examples":[1042]},"description":"The members of your organization to give access to the connection, by their `id` from `listMembers`. Depending on the BI tool, some may still have to enter their own credentials in the app, such as a Lightdash personal access token, before their access works: `isActive` in the response tells you which. Members whose access was suspended get it back. Members who already have access, and ids that aren't active members of your organization, are skipped. From 1 to 100 ids."}},"required":["userIds"],"additionalProperties":false}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"array","items":{"type":"object","properties":{"userId":{"type":"number","description":"Identifies a member who got access with this request, as their `id` in `listMembers`. Members who were skipped aren't listed."},"isActive":{"type":"boolean","description":"Whether the user's access to the connection is set up and working, shown as Active or Inactive in the connection's list of users in the app. It is `false`, for example, until a Lightdash user enters their personal access token in the app, or when Rollstack couldn't connect to Tableau as that user. It is also `false` while their access is suspended."}},"required":["userId","isActive"],"additionalProperties":false}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/connections/{type}/{id}/users/{userId}":{"delete":{"operationId":"removeConnectionUser","summary":"Suspend connection user","description":"Suspends a user's access to a connection. Their syncs stay but stop updating until `addConnectionUsers` gives them access again or someone takes their reports over. Only its admins may, and never for the default user.\n\nRequires the `connections:write` scope.","tags":["Connection users"],"x-scope":"connections:write","security":[{"apiKey":[]},{"oauth2":["connections:write"]}],"parameters":[{"name":"type","in":"path","required":true,"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`.","schema":{"type":"string","enum":["Tableau","Looker","Metabase","PowerBI","Lightdash","Omni","Sigma","Salesforce","Snowflake","Databricks"],"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`."}},{"name":"id","in":"path","required":true,"description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`.","schema":{"type":"string","description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`."}},{"name":"userId","in":"path","required":true,"description":"The member to act on, by their `id` from `listMembers`. For `removeConnectionUser`, one of the connection's users, as listed by `listConnectionUsers`. For `setConnectionAdmin`, any active member of your organization except the connection's owner. For `removeConnectionAdmin`, one of the connection's admins, as listed in `admins` by `getConnection`, except its owner.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The member to act on, by their `id` from `listMembers`. For `removeConnectionUser`, one of the connection's users, as listed by `listConnectionUsers`. For `setConnectionAdmin`, any active member of your organization except the connection's owner. For `removeConnectionAdmin`, one of the connection's admins, as listed in `admins` by `getConnection`, except its owner."}}],"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/connections/{type}/{id}/admins/{userId}":{"put":{"operationId":"setConnectionAdmin","summary":"Add connection admin","description":"Makes an active member an admin of a connection. Only its owner may.\n\nRequires the `connections:write` scope.","tags":["Connection admins"],"x-scope":"connections:write","security":[{"apiKey":[]},{"oauth2":["connections:write"]}],"parameters":[{"name":"type","in":"path","required":true,"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`.","schema":{"type":"string","enum":["Tableau","Looker","Metabase","PowerBI","Lightdash","Omni","Sigma","Salesforce","Snowflake","Databricks"],"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`."}},{"name":"id","in":"path","required":true,"description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`.","schema":{"type":"string","description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`."}},{"name":"userId","in":"path","required":true,"description":"The member to act on, by their `id` from `listMembers`. For `removeConnectionUser`, one of the connection's users, as listed by `listConnectionUsers`. For `setConnectionAdmin`, any active member of your organization except the connection's owner. For `removeConnectionAdmin`, one of the connection's admins, as listed in `admins` by `getConnection`, except its owner.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The member to act on, by their `id` from `listMembers`. For `removeConnectionUser`, one of the connection's users, as listed by `listConnectionUsers`. For `setConnectionAdmin`, any active member of your organization except the connection's owner. For `removeConnectionAdmin`, one of the connection's admins, as listed in `admins` by `getConnection`, except its owner."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"role":{"type":"string","enum":["admin"],"description":"The role to give the member on the connection. Only `admin` is accepted: admins manage the connection's users and can change its settings and credentials, while only the owner can delete the connection or add and remove admins. Ownership can be transferred only in the app. Being an admin doesn't make them one of the connection's users: add them with `addConnectionUsers` too if they need access of their own."}},"required":["role"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"userId":{"type":"number","description":"The member who is now an admin of the connection, as their `id` in `listMembers`."},"role":{"type":"string","enum":["owner","admin"],"description":"The member's role on the connection, always `admin` here. Admins manage the connection's users, settings and credentials. The other role, `owner`, belongs to the connection's owner, who can also delete the connection and choose its admins; it can't be given through the API."}},"required":["userId","role"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"removeConnectionAdmin","summary":"Remove connection admin","description":"Removes an admin of a connection. Only its owner may, and the owner's own role stays.\n\nRequires the `connections:write` scope.","tags":["Connection admins"],"x-scope":"connections:write","security":[{"apiKey":[]},{"oauth2":["connections:write"]}],"parameters":[{"name":"type","in":"path","required":true,"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`.","schema":{"type":"string","enum":["Tableau","Looker","Metabase","PowerBI","Lightdash","Omni","Sigma","Salesforce","Snowflake","Databricks"],"description":"The data source the connection reads from: `Tableau`, `Looker`, `Metabase`, `PowerBI`, `Lightdash`, `Omni`, `Sigma` or `Salesforce`, or the `Snowflake` or `Databricks` data warehouse. Endpoints that act on a connection take it in their path, with the connection's `id`."}},{"name":"id","in":"path","required":true,"description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`.","schema":{"type":"string","description":"Unique identifier for the connection, from `listConnections`, which also returns its `type`."}},{"name":"userId","in":"path","required":true,"description":"The member to act on, by their `id` from `listMembers`. For `removeConnectionUser`, one of the connection's users, as listed by `listConnectionUsers`. For `setConnectionAdmin`, any active member of your organization except the connection's owner. For `removeConnectionAdmin`, one of the connection's admins, as listed in `admins` by `getConnection`, except its owner.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The member to act on, by their `id` from `listMembers`. For `removeConnectionUser`, one of the connection's users, as listed by `listConnectionUsers`. For `setConnectionAdmin`, any active member of your organization except the connection's owner. For `removeConnectionAdmin`, one of the connection's admins, as listed in `admins` by `getConnection`, except its owner."}}],"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/spreadsheets":{"get":{"operationId":"searchSpreadsheets","summary":"Search spreadsheets","description":"The Google Sheets and Excel files the user added in the app whose name holds any word of query, in any case, most words first, at most 50. Rollstack can't search the user's whole Google Drive or OneDrive: for another file, ask the user to add it in the app. Confirm the file with the user, then list its sheets with getSpreadsheet.\n\nRequires the `connections:read` scope.","tags":["Spreadsheets"],"x-scope":"connections:read","security":[{"apiKey":[]},{"oauth2":["connections:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"query","in":"query","required":false,"description":"Words to search for in names, separated by spaces: a dashboard or spreadsheet is returned when its name contains any of them, case-insensitively. If omitted, results aren't filtered by name. At most 50 results are returned either way.","schema":{"description":"Words to search for in names, separated by spaces: a dashboard or spreadsheet is returned when its name contains any of them, case-insensitively. If omitted, results aren't filtered by name. At most 50 results are returned either way.","examples":["revenue"],"type":"string","minLength":1}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the spreadsheet in Rollstack, not the file's id in Google Drive, OneDrive or SharePoint. Pass it as `id` to `getSpreadsheet` to list its sheets, and as `spreadsheetId` to `addReportDatasheets`."},"name":{"type":"string","description":"The spreadsheet's name, as it was when the file was added to Rollstack: renaming the file afterwards in Google Sheets or Excel doesn't change it here. `searchSpreadsheets` matches `query` against it."},"type":{"type":"string","enum":["GoogleSheet","MicrosoftExcel"],"description":"Which app the spreadsheet belongs to, and so which of your accounts Rollstack reads it with. `GoogleSheet` is a Google Sheets file, read with your Google account. `MicrosoftExcel` is an Excel workbook in OneDrive or SharePoint, read with your Microsoft account. Excel files stored in Google Drive aren't available through the API."},"url":{"type":"string","description":"Link that opens the spreadsheet in Google Sheets or in Excel for the web, for example to check it's the right file before you add it to a report."}},"required":["id","name","type","url"],"additionalProperties":false}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/spreadsheets/{id}":{"get":{"operationId":"getSpreadsheet","summary":"Get spreadsheet","description":"A Google Sheets or Excel file the user added in the app, with its sheets, read with the user's own Google or Microsoft account. Fails with user-missing-oauth when the user hasn't connected that account in the app. Find the file's id with searchSpreadsheets, then add a range of one of its sheets to a report with addReportDatasheets by the sheet's id.\n\nRequires the `connections:read` scope.","tags":["Spreadsheets"],"x-scope":"connections:read","security":[{"apiKey":[]},{"oauth2":["connections:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[{"name":"id","in":"path","required":true,"description":"The spreadsheet whose sheets to list, by its `id` from `searchSpreadsheets`. This is Rollstack's identifier, not the file's id in Google Drive, OneDrive or SharePoint. It must be one of your own spreadsheets in Rollstack: another member's spreadsheet returns `404`, as does an Excel file stored in Google Drive.","schema":{"type":"string","description":"The spreadsheet whose sheets to list, by its `id` from `searchSpreadsheets`. This is Rollstack's identifier, not the file's id in Google Drive, OneDrive or SharePoint. It must be one of your own spreadsheets in Rollstack: another member's spreadsheet returns `404`, as does an Excel file stored in Google Drive."}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the spreadsheet in Rollstack, not the file's id in Google Drive, OneDrive or SharePoint. Pass it as `id` to `getSpreadsheet` to list its sheets, and as `spreadsheetId` to `addReportDatasheets`."},"name":{"type":"string","description":"The spreadsheet's name, as it was when the file was added to Rollstack: renaming the file afterwards in Google Sheets or Excel doesn't change it here. `searchSpreadsheets` matches `query` against it."},"type":{"type":"string","enum":["GoogleSheet","MicrosoftExcel"],"description":"Which app the spreadsheet belongs to, and so which of your accounts Rollstack reads it with. `GoogleSheet` is a Google Sheets file, read with your Google account. `MicrosoftExcel` is an Excel workbook in OneDrive or SharePoint, read with your Microsoft account. Excel files stored in Google Drive aren't available through the API."},"url":{"type":"string","description":"Link that opens the spreadsheet in Google Sheets or in Excel for the web, for example to check it's the right file before you add it to a report."},"sheets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the sheet within the spreadsheet. Pass it as `sheetId` to `addReportDatasheets`, with the spreadsheet's `id` as `spreadsheetId` and the cells to read as `range`. In Google Sheets, it is the number after `gid=` in the sheet's URL."},"title":{"type":"string","description":"The sheet's name, as shown on its tab in Google Sheets or Excel."}},"required":["id","title"],"additionalProperties":false},"description":"The sheets (tabs) in the spreadsheet as they are now in Google Sheets or Excel, hidden ones included. Pass a sheet's `id` as `sheetId` to `addReportDatasheets` to add a range of its cells to a report."}},"required":["id","name","type","url","sheets"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/smtp-connections":{"get":{"operationId":"listSmtpConnections","summary":"List SMTP connections","description":"The user's SMTP connections and the ones shared with the organization, without their credentials.\n\nRequires the `smtp:read` scope.","tags":["SMTP connections"],"x-scope":"smtp:read","security":[{"apiKey":[]},{"oauth2":["smtp:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the SMTP connection. Pass it as `smtpServerId` to `updateReportEmailConfig` to send a report's emails through it, or as `id` to `deleteSmtpConnection`."},"from":{"type":"string","description":"The sender address report emails sent through this connection go out from, as `email@domain.com` or `Name <email@domain.com>`."},"type":{"type":"string","enum":["login","oauth2"],"description":"How the connection sends report emails. `login` signs in to an SMTP server with a username and password (see `host`, `port` and `username`). `oauth2` sends through a Google or Microsoft account its owner connected to Rollstack (see `service`), with no password stored, and only while that account stays connected with permission to send email."},"service":{"anyOf":[{"type":"string","enum":["gmail_oauth","gmail","outlook","resend","manual"]},{"type":"null"}],"description":"Which account or server the connection sends through:\n\n- `gmail`: Gmail, from the owner's Google account with the same email as their Rollstack account.\n- `gmail_oauth`: Gmail, from another Google account the owner connected for sending.\n- `outlook`: Outlook, from the owner's Microsoft account.\n- `manual`: an SMTP server set up by hand with `host`, `port`, `username` and a password (`type` `login`).\n- `resend`: Rollstack's own sending service, which report emails use when no connection is chosen. No connection created in the app or the API has it.\n\n`null` when no service is recorded; the app shows such a connection as Manual."},"host":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The address of the SMTP server a `login` connection signs in to, such as `smtp.acme.com`. `null` for an `oauth2` connection, which sends through a Google or Microsoft account rather than an SMTP server."},"port":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The port Rollstack connects to on the SMTP server of a `login` connection. `null` for an `oauth2` connection."},"username":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"For a `login` connection, the username Rollstack signs in to the SMTP server with. For an `oauth2` connection, the email address recorded when it was created; emails go out through the account `service` points to, which for `gmail_oauth` may be another of the owner's connected Google accounts. Never `null` on connections created in the app or the API."},"organizationShared":{"type":"boolean","description":"Whether the connection is shared with the organization. When `true`, every member can choose it as the sender of their reports' emails, which then go out through the owner's account or server login. When `false`, only the owner can choose it. A shared connection can't be deleted until an owner or admin unshares it in the app."},"ownerUserId":{"type":"number","description":"The member who added the connection and owns it, as their `id` in `listMembers`; your own connections carry your `id` from `getMe`. Only the owner can delete the connection, and an `oauth2` connection sends through the owner's account."},"createdAt":{"description":"When the connection was added. `listSmtpConnections` lists the newest first.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","from","type","service","host","port","username","organizationShared","ownerUserId","createdAt"],"additionalProperties":false}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createSmtpConnection","summary":"Create SMTP connection","description":"Adds an SMTP connection after sending a test email through it. Only owners and admins may share it with the organization.\n\nRequires the `smtp:write` scope.","tags":["SMTP connections"],"x-scope":"smtp:write","security":[{"apiKey":[]},{"oauth2":["smtp:write"]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"oauth2","description":"Set to `oauth2` to send report emails through a Google or Microsoft account you connected to Rollstack, chosen with `service`, rather than through an SMTP server. Rollstack stores no password for it, and the connection sends only while that account stays connected with permission to send email."},"service":{"type":"string","enum":["gmail","outlook","gmail_oauth"],"description":"Which of your accounts sends the emails. `gmail` is Gmail, from the Google account with the same email as your Rollstack account. `gmail_oauth` is Gmail, from another Google account you connected for sending. `outlook` is Outlook, from your Microsoft account. The account must already be connected with permission to send email, under Settings > Connected apps > Sending email in the app, or creating the connection fails. Connecting an account there already creates an SMTP connection for it, which `listSmtpConnections` returns."},"username":{"type":"string","description":"The email address of the Google or Microsoft account the connection is for, recorded to tell your connections apart. It doesn't choose the account that sends: emails go out through the account `service` points to, and with `gmail_oauth` and several Google accounts connected for sending, that may not be this one. If you already have a connection with the same `service` and `username`, Rollstack returns it instead of creating another, keeping its `from`; with `organizationSmtpConfig` `true`, it also shares it.","examples":["reports@acme.com"]},"from":{"type":"string","description":"The sender address report emails sent through this connection go out from, as `email@domain.com` or `Name <email@domain.com>`. Rollstack sends a test email from it before saving the connection; if that email fails, the connection isn't created.","examples":["Acme Reports <reports@acme.com>"]},"organizationSmtpConfig":{"description":"Whether to share the connection with your organization, so every member can choose it as the sender of their reports' emails; their emails then go out through your account or server login. Only owners and admins can share a connection: anyone else passing `true` gets a `403`. If omitted or `false`, only you can choose it as a sender.","type":"boolean"}},"required":["type","service","username","from"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"login","description":"Set to `login` to send report emails through an SMTP server that Rollstack signs in to with `username` and `password`, such as your company's mail server or an email provider's SMTP service."},"service":{"type":"string","enum":["manual"],"description":"Always `manual`: the SMTP server is set up by hand with `host`, `port`, `username` and `password`, like the Manual option in the app."},"host":{"type":"string","description":"The address of the SMTP server to send through, as your email provider or IT team gives it.","examples":["smtp.acme.com"]},"port":{"type":"number","enum":[25,465,587,2525],"description":"The port Rollstack connects to on the SMTP server. Rollstack starts TLS as soon as it connects (implicit TLS, usually on port `465`), so the server must accept TLS on that port from the start, not only after STARTTLS."},"username":{"type":"string","description":"The username Rollstack signs in to the SMTP server with, often the mailbox's email address.","examples":["reports@acme.com"]},"password":{"type":"string","description":"The password Rollstack signs in to the SMTP server with. For a Gmail or Outlook mailbox, this is usually an app password. The API never returns it.","examples":["your-smtp-password"]},"from":{"type":"string","description":"The sender address report emails sent through this connection go out from, as `email@domain.com` or `Name <email@domain.com>`. Rollstack sends a test email from it before saving the connection; if that email fails, the connection isn't created.","examples":["Acme Reports <reports@acme.com>"]},"organizationSmtpConfig":{"description":"Whether to share the connection with your organization, so every member can choose it as the sender of their reports' emails; their emails then go out through your account or server login. Only owners and admins can share a connection: anyone else passing `true` gets a `403`. If omitted or `false`, only you can choose it as a sender.","type":"boolean"}},"required":["type","service","host","port","username","password","from"],"additionalProperties":false}]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the SMTP connection. Pass it as `smtpServerId` to `updateReportEmailConfig` to send a report's emails through it, or as `id` to `deleteSmtpConnection`."},"from":{"type":"string","description":"The sender address report emails sent through this connection go out from, as `email@domain.com` or `Name <email@domain.com>`."},"type":{"type":"string","enum":["login","oauth2"],"description":"How the connection sends report emails. `login` signs in to an SMTP server with a username and password (see `host`, `port` and `username`). `oauth2` sends through a Google or Microsoft account its owner connected to Rollstack (see `service`), with no password stored, and only while that account stays connected with permission to send email."},"service":{"anyOf":[{"type":"string","enum":["gmail_oauth","gmail","outlook","resend","manual"]},{"type":"null"}],"description":"Which account or server the connection sends through:\n\n- `gmail`: Gmail, from the owner's Google account with the same email as their Rollstack account.\n- `gmail_oauth`: Gmail, from another Google account the owner connected for sending.\n- `outlook`: Outlook, from the owner's Microsoft account.\n- `manual`: an SMTP server set up by hand with `host`, `port`, `username` and a password (`type` `login`).\n- `resend`: Rollstack's own sending service, which report emails use when no connection is chosen. No connection created in the app or the API has it.\n\n`null` when no service is recorded; the app shows such a connection as Manual."},"host":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The address of the SMTP server a `login` connection signs in to, such as `smtp.acme.com`. `null` for an `oauth2` connection, which sends through a Google or Microsoft account rather than an SMTP server."},"port":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The port Rollstack connects to on the SMTP server of a `login` connection. `null` for an `oauth2` connection."},"username":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"For a `login` connection, the username Rollstack signs in to the SMTP server with. For an `oauth2` connection, the email address recorded when it was created; emails go out through the account `service` points to, which for `gmail_oauth` may be another of the owner's connected Google accounts. Never `null` on connections created in the app or the API."},"organizationShared":{"type":"boolean","description":"Whether the connection is shared with the organization. When `true`, every member can choose it as the sender of their reports' emails, which then go out through the owner's account or server login. When `false`, only the owner can choose it. A shared connection can't be deleted until an owner or admin unshares it in the app."},"ownerUserId":{"type":"number","description":"The member who added the connection and owns it, as their `id` in `listMembers`; your own connections carry your `id` from `getMe`. Only the owner can delete the connection, and an `oauth2` connection sends through the owner's account."},"createdAt":{"description":"When the connection was added. `listSmtpConnections` lists the newest first.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","from","type","service","host","port","username","organizationShared","ownerUserId","createdAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/smtp-connections/{id}":{"delete":{"operationId":"deleteSmtpConnection","summary":"Delete SMTP connection","description":"Deletes one of your SMTP connections. One shared with the organization must be unshared in the app first.\n\nRequires the `smtp:write` scope.","tags":["SMTP connections"],"x-scope":"smtp:write","security":[{"apiKey":[]},{"oauth2":["smtp:write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The SMTP connection to delete, by its `id` from `listSmtpConnections`. It must be one you added: another member's connection returns `404`, even when shared with the organization. Reports set to send through it then send their emails from Rollstack instead.","schema":{"type":"string","description":"The SMTP connection to delete, by its `id` from `listSmtpConnections`. It must be one you added: another member's connection returns `404`, even when shared with the organization. Reports set to send through it then send their emails from Rollstack instead."}}],"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/folders":{"get":{"operationId":"listFolders","summary":"List folders","description":"The folders the user can see, each with its parent, null at the top level, and the user's permission on it: null, view, edit or manage. Pass a folder's id as folderId to listReports or createReport.\n\nRequires the `slide_decks:read` scope.","tags":["Folders"],"x-scope":"slide_decks:read","security":[{"apiKey":[]},{"oauth2":["slide_decks:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the folder. Pass it as `folderId` to `listReports` to list the reports in it, or to `createReport` or `updateReport` to put a report in it."},"name":{"type":"string","description":"The folder's name, as shown in Rollstack."},"parentFolderId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The folder this one is nested in. `null` for a folder at the top level. The parent is missing from the list when you can see this folder but not its parent."},"permission":{"anyOf":[{"type":"string","enum":["view","edit","manage"]},{"type":"null"}],"description":"What you can do in the folder. `view` lets you open the reports in it, `edit` also lets you change them, and `manage` also lets you share the folder and change who has access to it. It is the highest of what the folder is shared with you directly and what you get from the folders it is nested in, where owning one of those gives `manage`. `null` when you own the folder and get nothing from a parent folder, as with a top-level folder you created: as its owner, you can do everything in it."}},"required":["id","name","parentFolderId","permission"],"additionalProperties":false}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/organization":{"get":{"operationId":"getOrganization","summary":"Get organization","description":"The API key's organization and its settings: its name and default timezone, the email domains members may be invited from, how reports update and link to their sources, and which features are on.\n\nRequires the `organization:read` scope.","tags":["Organization"],"x-scope":"organization:read","security":[{"apiKey":[]},{"oauth2":["organization:read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the organization: the same `id` that `getMe` returns in `organization`."},"name":{"type":"string","description":"The organization's name, as shown in Rollstack."},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The organization's default timezone for reports. Reports created while it is set, including with `createReport`, start with it as their `timezone`; changing it doesn't change the `timezone` of existing reports. For reports that update a file in your drive, such as Google Slides presentations, it also replaces each report's own timezone for its date variables. `null` means no default. An IANA timezone name, such as `America/New_York`."},"allowedDomains":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"The organization's domain allowlist, such as `acme.com`: the email domains people can be invited to the organization from. While it is empty or `null`, invites from the app aren't limited by domain, but `createInvites` fails with `invites-require-allowed-domains`. Owners and admins edit it in the organization settings in Rollstack; the API can't change it. A domain matches exactly, ignoring case, so `acme.com` doesn't cover `eu.acme.com`."},"updateMethod":{"anyOf":[{"type":"string","enum":["update","archive","updateVisualizations"]},{"type":"null"}],"description":"How reports that update a file in your drive, such as Google Slides or PowerPoint presentations, change that file when they run. The reports this API manages don't use it. `update` updates the same file with the latest data. `archive` first saves a copy of the file, named with the date of its previous run, then updates the original; runs that update only some of the report's visualizations skip the copy. `updateVisualizations` is the method email reports are created with; the app doesn't offer it as an organization setting. While set, every such report uses it instead of its own update method; `null` lets each report use its own."},"linkOption":{"anyOf":[{"type":"string","enum":["nolink","rollstack","external"]},{"type":"null"}],"description":"Where a click on a visualization's image leads, in reports that update a file in your drive, such as Google Slides presentations. The reports this API manages don't use it. `rollstack` opens the visualization's page in Rollstack, `external` opens the dashboard or spreadsheet it comes from, and `nolink` leaves images without a link. While set, every such report uses it instead of its own link option; `null` lets each report use its own."},"llmProvider":{"type":"string","enum":["openai","azure_openai","google_gemini","amazon_bedrock","google_ai_studio","google_vertex_ai","anthropic","custom_provider"],"description":"The AI provider Rollstack tries first when it writes the organization's Insights, such as `openai`, `azure_openai` or `amazon_bedrock`; another provider may write them as a fallback. It isn't the custom LLM provider the slides agent runs on, which `getLLMProvider` returns. The API can't change it. `custom_provider` is a legacy value."},"insightsEnabled":{"type":"boolean","description":"Whether the organization's reports can have Insights: AI-written commentary on the data in a report's visualizations. While off, no one can add or edit Insights, and runs leave existing ones unchanged."},"memoriesEnabled":{"type":"boolean","description":"Whether members can use AI Memories: personal notes the AI draws on when it writes their Insights, such as to write large numbers with K, M or B. Each member keeps theirs, grouped in profiles, on the Insight Memories settings page, which is hidden while AI Memories are off."},"spreadsheetsEnabled":{"type":"boolean","description":"Whether Rollstack offers Google Sheets and Microsoft Excel spreadsheets as data sources. While off, the app no longer offers them when someone adds a data source. Only the app checks this setting."},"emailAnalyticsEnabled":{"type":"boolean","description":"Whether Rollstack can track when report emails are opened. While on, a report's emails are tracked once its email settings turn email analytics on (`emailAnalyticsEnabled`). While off, no report email is tracked, whatever its settings say."}},"required":["id","name","timezone","allowedDomains","updateMethod","linkOption","llmProvider","insightsEnabled","memoriesEnabled","spreadsheetsEnabled","emailAnalyticsEnabled"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateOrganization","summary":"Update organization","description":"Changes the API key's organization settings. Send only the fields to change, at least one; null clears the timezone, update method or link option.\n\nRequires the `organization:write` scope. Only owners and admins of the organization may call it.","tags":["Organization"],"x-scope":"organization:write","security":[{"apiKey":[]},{"oauth2":["organization:write"]}],"x-admin-only":true,"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"description":"The organization's new name, as shown to its members in Rollstack.","examples":["Acme"],"type":"string"},"timezone":{"description":"The organization's default timezone for reports. Reports created while it is set, including with `createReport`, start with it as their `timezone`; changing it doesn't change the `timezone` of existing reports. For reports that update a file in your drive, such as Google Slides presentations, it also replaces each report's own timezone for its date variables. `null` means no default. An IANA timezone name, such as `America/New_York`.","examples":["America/New_York"],"anyOf":[{"type":"string"},{"type":"null"}]},"updateMethod":{"description":"How reports that update a file in your drive, such as Google Slides or PowerPoint presentations, change that file when they run. The reports this API manages don't use it. `update` updates the same file with the latest data. `archive` first saves a copy of the file, named with the date of its previous run, then updates the original; runs that update only some of the report's visualizations skip the copy. `updateVisualizations` is the method email reports are created with; the app doesn't offer it as an organization setting. While set, every such report uses it instead of its own update method; `null` lets each report use its own.","anyOf":[{"type":"string","enum":["update","archive","updateVisualizations"]},{"type":"null"}]},"linkOption":{"description":"Where a click on a visualization's image leads, in reports that update a file in your drive, such as Google Slides presentations. The reports this API manages don't use it. `rollstack` opens the visualization's page in Rollstack, `external` opens the dashboard or spreadsheet it comes from, and `nolink` leaves images without a link. While set, every such report uses it instead of its own link option; `null` lets each report use its own.","anyOf":[{"type":"string","enum":["nolink","rollstack","external"]},{"type":"null"}]},"insightsEnabled":{"description":"Whether the organization's reports can have Insights: AI-written commentary on the data in a report's visualizations. While off, no one can add or edit Insights, and runs leave existing ones unchanged. Only owners can change it, not admins.","type":"boolean"},"restrictInsightUsers":{"description":"Whether only the members you pick can use Insights, rather than everyone in the organization. Pick them with each member's `insightsEnabled` in `updateMember`. `getOrganization` doesn't return this setting. Only owners can change it, not admins.","type":"boolean"},"memoriesEnabled":{"description":"Whether members can use AI Memories: personal notes the AI draws on when it writes their Insights, such as to write large numbers with K, M or B. Each member keeps theirs, grouped in profiles, on the Insight Memories settings page, which is hidden while AI Memories are off. Only owners can change it, not admins.","type":"boolean"},"spreadsheetsEnabled":{"description":"Whether Rollstack offers Google Sheets and Microsoft Excel spreadsheets as data sources. While off, the app no longer offers them when someone adds a data source. Only the app checks this setting. Only owners can change it, not admins.","type":"boolean"},"emailAnalyticsEnabled":{"description":"Whether Rollstack can track when report emails are opened. While on, a report's emails are tracked once its email settings turn email analytics on (`emailAnalyticsEnabled`). While off, no report email is tracked, whatever its settings say. Only owners can change it, not admins.","type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the organization: the same `id` that `getMe` returns in `organization`."},"name":{"type":"string","description":"The organization's name, as shown in Rollstack."},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The organization's default timezone for reports. Reports created while it is set, including with `createReport`, start with it as their `timezone`; changing it doesn't change the `timezone` of existing reports. For reports that update a file in your drive, such as Google Slides presentations, it also replaces each report's own timezone for its date variables. `null` means no default. An IANA timezone name, such as `America/New_York`."},"allowedDomains":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"The organization's domain allowlist, such as `acme.com`: the email domains people can be invited to the organization from. While it is empty or `null`, invites from the app aren't limited by domain, but `createInvites` fails with `invites-require-allowed-domains`. Owners and admins edit it in the organization settings in Rollstack; the API can't change it. A domain matches exactly, ignoring case, so `acme.com` doesn't cover `eu.acme.com`."},"updateMethod":{"anyOf":[{"type":"string","enum":["update","archive","updateVisualizations"]},{"type":"null"}],"description":"How reports that update a file in your drive, such as Google Slides or PowerPoint presentations, change that file when they run. The reports this API manages don't use it. `update` updates the same file with the latest data. `archive` first saves a copy of the file, named with the date of its previous run, then updates the original; runs that update only some of the report's visualizations skip the copy. `updateVisualizations` is the method email reports are created with; the app doesn't offer it as an organization setting. While set, every such report uses it instead of its own update method; `null` lets each report use its own."},"linkOption":{"anyOf":[{"type":"string","enum":["nolink","rollstack","external"]},{"type":"null"}],"description":"Where a click on a visualization's image leads, in reports that update a file in your drive, such as Google Slides presentations. The reports this API manages don't use it. `rollstack` opens the visualization's page in Rollstack, `external` opens the dashboard or spreadsheet it comes from, and `nolink` leaves images without a link. While set, every such report uses it instead of its own link option; `null` lets each report use its own."},"llmProvider":{"type":"string","enum":["openai","azure_openai","google_gemini","amazon_bedrock","google_ai_studio","google_vertex_ai","anthropic","custom_provider"],"description":"The AI provider Rollstack tries first when it writes the organization's Insights, such as `openai`, `azure_openai` or `amazon_bedrock`; another provider may write them as a fallback. It isn't the custom LLM provider the slides agent runs on, which `getLLMProvider` returns. The API can't change it. `custom_provider` is a legacy value."},"insightsEnabled":{"type":"boolean","description":"Whether the organization's reports can have Insights: AI-written commentary on the data in a report's visualizations. While off, no one can add or edit Insights, and runs leave existing ones unchanged."},"memoriesEnabled":{"type":"boolean","description":"Whether members can use AI Memories: personal notes the AI draws on when it writes their Insights, such as to write large numbers with K, M or B. Each member keeps theirs, grouped in profiles, on the Insight Memories settings page, which is hidden while AI Memories are off."},"spreadsheetsEnabled":{"type":"boolean","description":"Whether Rollstack offers Google Sheets and Microsoft Excel spreadsheets as data sources. While off, the app no longer offers them when someone adds a data source. Only the app checks this setting."},"emailAnalyticsEnabled":{"type":"boolean","description":"Whether Rollstack can track when report emails are opened. While on, a report's emails are tracked once its email settings turn email analytics on (`emailAnalyticsEnabled`). While off, no report email is tracked, whatever its settings say."}},"required":["id","name","timezone","allowedDomains","updateMethod","linkOption","llmProvider","insightsEnabled","memoriesEnabled","spreadsheetsEnabled","emailAnalyticsEnabled"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/me":{"get":{"operationId":"getMe","summary":"Get current user","description":"The user and API key making the request: the user's id, name and email, the organization the key belongs to with the role the key acts with, and the key's id and scopes. Call it to check that a key works.\n\nWorks with any valid API key.","tags":["Members"],"x-scope":null,"security":[{"apiKey":[]},{"oauth2":[]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"number","description":"Unique identifier for the user the API key belongs to: the same `id` that `listMembers` returns for them."},"email":{"type":"string","description":"The email address of the user the API key belongs to."},"name":{"type":"string","description":"The name of the user the API key belongs to, as shown in Rollstack."},"organization":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the organization: the same `id` that `getOrganization` returns."},"name":{"type":"string","description":"The organization's name, as shown in Rollstack."},"role":{"type":"string","enum":["owner","admin","member"],"description":"The role the API key acts with in the organization, which limits what it can do on top of its scopes. As an `owner` or `admin`, the key can call the endpoints limited to owners and admins, but only as an `owner` can it turn the organization's features on or off or change who can access its Authentication settings. As a `member`, it can do neither. It is the user's current role, but never higher than the one they had when the key was created or its scopes were last edited, so promoting the user doesn't raise it."}},"required":["id","name","role"],"additionalProperties":false,"description":"The organization the API key belongs to. A key works only in the organization it was created in."},"apiKey":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the API key that made the request. It identifies the key without revealing its secret."},"scopes":{"type":"array","items":{"type":"string","enum":["organization:read","organization:write","users:read","users:write","connections:read","connections:write","credentials:write","smtp:read","smtp:write","slide_decks:read","slide_decks:write","slide_decks:run","slide_decks:email"]},"description":"The scopes the API key carries, which decide the endpoints it can call: each endpoint states the scope it needs, and the Scopes section of the introduction lists what each one allows. While the key acts as a `member`, it loses `users:read`, `users:write` and `organization:write`, the scopes only owners and admins may grant, even if it was created with them."}},"required":["id","scopes"],"additionalProperties":false,"description":"The API key that made the request."}},"required":["id","email","name","organization","apiKey"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/members":{"get":{"operationId":"listMembers","summary":"List members","description":"The members of the organization, with their role, authentication role, insights access and whether they are active. Optionally only those with a status, active or deactivated, or with an email.\n\nRequires the `users:read` scope. Only owners and admins of the organization may call it.","tags":["Members"],"x-scope":"users:read","security":[{"apiKey":[]},{"oauth2":["users:read"]}],"x-mcp":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"x-admin-only":true,"parameters":[{"name":"status","in":"query","required":false,"description":"Only return `active` members, or only `deactivated` ones. If omitted, returns both.","schema":{"description":"Only return `active` members, or only `deactivated` ones. If omitted, returns both.","type":"string","enum":["active","deactivated"]}},{"name":"email","in":"query","required":false,"description":"Only return the member with exactly this email address, ignoring case. Returns an empty list if no member has it, or if they don't match `status`.","schema":{"description":"Only return the member with exactly this email address, ignoring case. Returns an empty list if no member has it, or if they don't match `status`.","examples":["jane@acme.com"],"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"array","items":{"type":"object","properties":{"id":{"type":"number","description":"Unique identifier for the member. Pass it as `userId` to `updateMember`, `deactivateMember` or `reactivateMember`."},"email":{"type":"string","description":"The email address of the member's Rollstack account."},"name":{"type":"string","description":"The member's name, as shown in Rollstack."},"role":{"type":"string","enum":["owner","admin","member"],"description":"The member's role in the organization. `owner` can do everything, including turning the organization's features on or off, choosing who can access its Authentication settings and, in the app, making other members owners. `admin` manages the organization's settings, members and invites, but can't turn features such as Insights or email analytics on or off, or change, deactivate or reactivate owners. `member` uses Rollstack without managing the organization."},"authenticationRole":{"anyOf":[{"type":"string","enum":["viewer","editor"]},{"type":"null"}],"description":"The member's access to the organization's Authentication settings, where Single Sign-On (SSO) and SCIM provisioning are set up: `viewer` can see them, `editor` can also change them, and `null` gives no access. Owners always have full access, whatever this value."},"insightsEnabled":{"type":"boolean","description":"Whether the member can use Insights while the organization restricts them to the members it picks (`restrictInsightUsers` in `updateOrganization`). It has no effect while Insights are open to every member or turned off."},"status":{"type":"string","enum":["active","deactivated"],"description":"Whether the member has access to the organization. `active` members do. `deactivated` members were removed from it, which revoked their API keys; `reactivateMember` restores their access, but not their keys."},"deactivatedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the member was deactivated. `null` while they're active."},"deactivationReason":{"anyOf":[{"type":"string","enum":["left_company","no_longer_needs_access","not_using_enough","too_expensive","switching_tool","duplicate_account","sso_deprovisioned","other"]},{"type":"null"}],"description":"Why the member was deactivated: the reason an admin gave, or `sso_deprovisioned` when SSO removed them. `null` while they're active, or when no reason was given."},"deactivationReasonDetails":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the admin wrote when `deactivationReason` is `other`. `null` otherwise."}},"required":["id","email","name","role","authenticationRole","insightsEnabled","status","deactivatedAt","deactivationReason","deactivationReasonDetails"],"additionalProperties":false}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/members/{userId}":{"patch":{"operationId":"updateMember","summary":"Update member","description":"Changes a member's role, authentication role or insights access. Send only the fields to change, at least one. The role can be admin or member: a key never makes anyone an owner.\n\nRequires the `users:write` scope. Only owners and admins of the organization may call it.","tags":["Members"],"x-scope":"users:write","security":[{"apiKey":[]},{"oauth2":["users:write"]}],"x-admin-only":true,"parameters":[{"name":"userId","in":"path","required":true,"description":"The member to act on, by the `id` from `listMembers`. An id that is not a member of the organization returns `user-not-in-organization`.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The member to act on, by the `id` from `listMembers`. An id that is not a member of the organization returns `user-not-in-organization`."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"role":{"description":"The member's new role: `admin` to let them manage the organization's settings, members and invites, or `member` to take that away. A key can't make anyone an owner, admins can't change an owner's role, and you can't change your own.","type":"string","enum":["admin","member"]},"authenticationRole":{"description":"The member's access to the organization's Authentication settings, where Single Sign-On (SSO) and SCIM provisioning are set up: `viewer` can see them, `editor` can also change them, and `null` gives no access. Owners always have full access, whatever this value. Only owners can change it, not admins.","anyOf":[{"type":"string","enum":["viewer","editor"]},{"type":"null"}]},"insightsEnabled":{"description":"Whether the member can use Insights while the organization restricts them to the members it picks (`restrictInsightUsers` in `updateOrganization`). It has no effect while Insights are open to every member or turned off.","type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"number","description":"Unique identifier for the member. Pass it as `userId` to `updateMember`, `deactivateMember` or `reactivateMember`."},"email":{"type":"string","description":"The email address of the member's Rollstack account."},"name":{"type":"string","description":"The member's name, as shown in Rollstack."},"role":{"type":"string","enum":["owner","admin","member"],"description":"The member's role in the organization. `owner` can do everything, including turning the organization's features on or off, choosing who can access its Authentication settings and, in the app, making other members owners. `admin` manages the organization's settings, members and invites, but can't turn features such as Insights or email analytics on or off, or change, deactivate or reactivate owners. `member` uses Rollstack without managing the organization."},"authenticationRole":{"anyOf":[{"type":"string","enum":["viewer","editor"]},{"type":"null"}],"description":"The member's access to the organization's Authentication settings, where Single Sign-On (SSO) and SCIM provisioning are set up: `viewer` can see them, `editor` can also change them, and `null` gives no access. Owners always have full access, whatever this value."},"insightsEnabled":{"type":"boolean","description":"Whether the member can use Insights while the organization restricts them to the members it picks (`restrictInsightUsers` in `updateOrganization`). It has no effect while Insights are open to every member or turned off."},"status":{"type":"string","enum":["active","deactivated"],"description":"Whether the member has access to the organization. `active` members do. `deactivated` members were removed from it, which revoked their API keys; `reactivateMember` restores their access, but not their keys."},"deactivatedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the member was deactivated. `null` while they're active."},"deactivationReason":{"anyOf":[{"type":"string","enum":["left_company","no_longer_needs_access","not_using_enough","too_expensive","switching_tool","duplicate_account","sso_deprovisioned","other"]},{"type":"null"}],"description":"Why the member was deactivated: the reason an admin gave, or `sso_deprovisioned` when SSO removed them. `null` while they're active, or when no reason was given."},"deactivationReasonDetails":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the admin wrote when `deactivationReason` is `other`. `null` otherwise."}},"required":["id","email","name","role","authenticationRole","insightsEnabled","status","deactivatedAt","deactivationReason","deactivationReasonDetails"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/members/{userId}/deactivate":{"post":{"operationId":"deactivateMember","summary":"Deactivate member","description":"Deactivates a member, revokes their API keys and deletes their invites. Send the reason when you know it, so admins see why in the members list.\n\nRequires the `users:write` scope. Only owners and admins of the organization may call it.","tags":["Members"],"x-scope":"users:write","security":[{"apiKey":[]},{"oauth2":["users:write"]}],"x-admin-only":true,"parameters":[{"name":"userId","in":"path","required":true,"description":"The member to act on, by the `id` from `listMembers`. An id that is not a member of the organization returns `user-not-in-organization`.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The member to act on, by the `id` from `listMembers`. An id that is not a member of the organization returns `user-not-in-organization`."}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"reason":{"type":"string","enum":["left_company","no_longer_needs_access","not_using_enough","too_expensive","switching_tool","duplicate_account","other"],"description":"Why the member is deactivated. `other` needs `reasonDetails`."},"reasonDetails":{"description":"Why the member is deactivated, in your words. Required and kept only when `reason` is `other`.","type":"string","maxLength":500}},"required":["reason"]}}}},"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/members/{userId}/reactivate":{"post":{"operationId":"reactivateMember","summary":"Reactivate member","description":"Reactivates a deactivated member. Their revoked API keys stay revoked.\n\nRequires the `users:write` scope. Only owners and admins of the organization may call it.","tags":["Members"],"x-scope":"users:write","security":[{"apiKey":[]},{"oauth2":["users:write"]}],"x-admin-only":true,"parameters":[{"name":"userId","in":"path","required":true,"description":"The member to act on, by the `id` from `listMembers`. An id that is not a member of the organization returns `user-not-in-organization`.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The member to act on, by the `id` from `listMembers`. An id that is not a member of the organization returns `user-not-in-organization`."}}],"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/invites":{"get":{"operationId":"listInvites","summary":"List invites","description":"The pending invites of the organization, with the role and authentication role each user joins with, and when they were invited.\n\nRequires the `users:read` scope. Only owners and admins of the organization may call it.","tags":["Invites"],"x-scope":"users:read","security":[{"apiKey":[]},{"oauth2":["users:read"]}],"x-admin-only":true,"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the invite. Pass it as `inviteId` to `deleteInvite` to cancel the invite."},"email":{"type":"string","description":"The email address invited to join the organization."},"role":{"type":"string","enum":["owner","admin","member"],"description":"The role the person gets when they accept the invite. `owner` can do everything in the organization, `admin` manages its settings, members and invites, and `member` uses Rollstack without managing the organization."},"authenticationRole":{"anyOf":[{"type":"string","enum":["viewer","editor"]},{"type":"null"}],"description":"The access to the organization's Authentication settings (Single Sign-On and SCIM provisioning) the person gets when they accept the invite: `viewer` can see them, `editor` can also change them, and `null` gives none."},"createdAt":{"description":"When the person was invited.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","email","role","authenticationRole","createdAt"],"additionalProperties":false}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createInvites","summary":"Create invites","description":"Invites up to 50 users as admins or members. Only emails in the organization's allowed domains are invited, and it fails with a 400 while the organization has none. Returns the invites it created and the emails it rejected, with the reason: outside the allowed domains, already a member or already invited.\n\nRequires the `users:write` scope. Only owners and admins of the organization may call it.","tags":["Invites"],"x-scope":"users:write","security":[{"apiKey":[]},{"oauth2":["users:write"]}],"x-admin-only":true,"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"emails":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","examples":["jane@acme.com"]},"description":"The email addresses to invite. Each one on the organization's domain allowlist (`allowedDomains`) that doesn't belong to a member and isn't already invited gets an invite and an invitation email; the others come back in `rejected`. From 1 to 50 addresses, each listed once, ignoring case."},"role":{"type":"string","enum":["admin","member"],"description":"The role the invited people get when they join: `admin` lets them manage the organization's settings, members and invites, and `member` lets them use Rollstack without managing the organization. A key can't invite owners."},"authenticationRole":{"description":"Gives the invited people access to the organization's Authentication settings (Single Sign-On and SCIM provisioning) once they join: `viewer` can see them, `editor` can also change them. If omitted, they join without access. Only owners can set it, not admins.","type":"string","enum":["viewer","editor"]}},"required":["emails","role"],"additionalProperties":false}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"invited":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the invite. Pass it as `inviteId` to `deleteInvite` to cancel the invite."},"email":{"type":"string","description":"The email address invited to join the organization."},"role":{"type":"string","enum":["owner","admin","member"],"description":"The role the person gets when they accept the invite. `owner` can do everything in the organization, `admin` manages its settings, members and invites, and `member` uses Rollstack without managing the organization."},"authenticationRole":{"anyOf":[{"type":"string","enum":["viewer","editor"]},{"type":"null"}],"description":"The access to the organization's Authentication settings (Single Sign-On and SCIM provisioning) the person gets when they accept the invite: `viewer` can see them, `editor` can also change them, and `null` gives none."},"createdAt":{"description":"When the person was invited.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","email","role","authenticationRole","createdAt"],"additionalProperties":false},"description":"The invites created, one for each email that passed the checks. Rollstack emails each person an invitation to join."},"rejected":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","description":"An email from your request that was not invited, in lowercase."},"reason":{"type":"string","enum":["domain_not_allowed","already_member","already_invited"],"description":"Why the email was not invited. `domain_not_allowed`: its domain isn't on the organization's `allowedDomains`. `already_member`: it belongs to a member of the organization, active or deactivated; reactivate a deactivated one with `reactivateMember`. `already_invited`: it already has a pending invite, listed by `listInvites`."}},"required":["email","reason"],"additionalProperties":false},"description":"The emails that were not invited, each with the reason. The other emails in the request were still invited."}},"required":["invited","rejected"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/invites/{inviteId}":{"delete":{"operationId":"deleteInvite","summary":"Delete invite","description":"Deletes a pending invite.\n\nRequires the `users:write` scope. Only owners and admins of the organization may call it.","tags":["Invites"],"x-scope":"users:write","security":[{"apiKey":[]},{"oauth2":["users:write"]}],"x-admin-only":true,"parameters":[{"name":"inviteId","in":"path","required":true,"description":"The invite to delete, by the `id` from `listInvites` or `createInvites`. An unknown invite, or one from another organization, returns `invite-not-found`.","schema":{"type":"string","description":"The invite to delete, by the `id` from `listInvites` or `createInvites`. An unknown invite, or one from another organization, returns `invite-not-found`."}}],"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/organization/llm-provider":{"get":{"operationId":"getLLMProvider","summary":"Get LLM provider","description":"The organization's custom LLM provider, without its credentials. Only owners, and members an owner allowed to manage the AI provider, may call it.\n\nRequires the `organization:read` scope.","tags":["LLM provider"],"x-scope":"organization:read","security":[{"apiKey":[]},{"oauth2":["organization:read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the organization's LLM provider. It stays the same when you replace the provider with `setLLMProvider`; setting one up again after `deleteLLMProvider` gives a new one."},"type":{"type":"string","enum":["anthropic","openai","azure_foundry","amazon_bedrock","google_vertex_ai"],"description":"The provider the organization's slides agent runs on, instead of Rollstack's own AI providers: `anthropic` (the Anthropic API), `openai` (the OpenAI API), `azure_foundry` (an Azure AI Foundry resource), `amazon_bedrock` (Amazon Bedrock in an AWS account) or `google_vertex_ai` (Vertex AI in a Google Cloud project). Insights don't use it: they run on the organization's `llmProvider`, from `getOrganization`."},"auth":{"type":"string","enum":["apiKey","oidc"],"description":"How Rollstack signs in to the provider. With `apiKey`, it uses a secret saved with the provider: an API key or, on Google Vertex AI, a service account key. With `oidc`, the setup is keyless: your provider trusts short-lived tokens from Rollstack's OpenID Connect issuer for your organization, so no secret is saved."},"hasCredentials":{"type":"boolean","const":true,"description":"Whether the provider has saved credentials: always `true`. Its secrets, `apiKey` or `privateKey`, are never returned, not even in `settings`: to change them, send the whole setup again with `setLLMProvider`."},"settings":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The provider's saved setup without its secrets: the `credentials` it was last saved with, as in the `setLLMProvider` body, minus `apiKey` and `privateKey`. It contains `auth` and, depending on `type`: `dataResidency` (OpenAI); `resourceName` and `models` (Azure AI Foundry); `region`, `dataLocation` and `models` (Amazon Bedrock); or `projectId`, `region` and `models`, plus `clientEmail` with a service account key (Google Vertex AI). A keyless setup also contains its ids, such as `tenantId` and `clientId`, or `roleArn`."},"updatedAt":{"description":"When the provider was last saved, with `setLLMProvider` or in the app. Recording or clearing a `failure` doesn't change it.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedBy":{"anyOf":[{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The name of the member who last saved the provider, as shown in Rollstack."},"email":{"type":"string","description":"The email address of the member who last saved the provider."}},"required":["name","email"],"additionalProperties":false},{"type":"null"}],"description":"The member who last saved the provider, with `setLLMProvider` or in the app. When `failure` is set, Rollstack notifies them, or the organization's owners if they're no longer an active member. `null` if that user's account no longer exists."},"failure":{"anyOf":[{"type":"string","enum":["key_invalid","forbidden","model_not_found","out_of_credit"]},{"type":"null"}],"description":"Why the slides agent's calls to the provider are failing, when only a change on your provider's side can fix it. `null` while calls work. `key_invalid`: the provider doesn't accept the API key or the keyless sign-in. `forbidden`: the key or sign-in isn't allowed to use `failedModel`. `model_not_found`: `failedModel` isn't available to the account; on Azure AI Foundry, it isn't deployed under its own name, and on Amazon Bedrock or Google Vertex AI, it isn't enabled. `out_of_credit`: the provider account is out of credit. When it's set, Rollstack notifies the member in `updatedBy`, or the owners if they're no longer an active member. It's cleared once a call to `failedModel` works again or the provider is saved again."},"failedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When a slides agent call to the provider first failed with the current `failure`. `null` while calls work."},"failedModel":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The model whose call failed, such as `claude-haiku-5-5`. Until the provider is saved again, only a working call to this model clears `failure`, so a failing `fast` model stays flagged even while the `smart` one works. `null` while calls work."}},"required":["id","type","auth","hasCredentials","settings","updatedAt","updatedBy","failure","failedAt","failedModel"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"setLLMProvider","summary":"Replace LLM provider","description":"Creates or replaces the organization's custom LLM provider, on the Enterprise plan only. Only owners, and admins an owner allowed to manage the AI provider, may call it: members' keys can't carry organization:write. The keys are saved only once one short call on each of their models works: otherwise nothing is saved and the call fails with a 400 (code ai-provider-test-failed); the AI provider setting in the app says which model failed and why. Calls are limited to 10 a minute for each organization. Every owner gets an email when the provider is set up, replaced or deleted. Web search always runs on OpenAI, so saving a provider that sends the searches to Rollstack's OpenAI account (any provider but OpenAI on its global host) turns web search off, unless the organization already had that kind of provider; an owner can turn it back on.\n\nRequires the `organization:write` scope.","tags":["LLM provider"],"x-scope":"organization:write","security":[{"apiKey":[]},{"oauth2":["organization:write"]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"anthropic","description":"Runs the slides agent on your own Anthropic organization, through the Anthropic API, with Claude Opus 5.5 (`claude-opus-5-5`) for its main work and Claude Haiku 5.5 (`claude-haiku-5-5`) for its quick steps. There are no models to pick or deploy."},"credentials":{"oneOf":[{"type":"object","properties":{"auth":{"type":"string","const":"apiKey","description":"Rollstack signs in to the provider with a secret you send in this request: an API key or, on Google Vertex AI, a service account key (`clientEmail` and `privateKey`). Rollstack saves the secret and never returns it, so to change it, send the whole setup again."},"apiKey":{"type":"string","minLength":1,"description":"An Anthropic API key, created in the Claude Console under API keys, in a workspace for Rollstack where you can also set a spend limit. Rollstack never returns it.","examples":["your-anthropic-api-key"]}},"required":["auth","apiKey"]},{"type":"object","properties":{"auth":{"type":"string","const":"oidc","description":"Rollstack signs in without a saved secret: its OpenID Connect issuer signs a short-lived token for the subject `rollstack:org:<id>`, where `<id>` is your organization's `id` from `getOrganization`, and your provider exchanges the token for temporary credentials. Set up your provider to trust that issuer and to check that subject, so it accepts only your organization: `setLLMProvider` fails if the setup also accepts another organization's token. The AI provider setting in the app, under Settings › Features, shows the issuer, subject and audience to trust."},"anthropicOrganizationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$","description":"The ID of your Anthropic organization, the one where you added Rollstack's issuer in the Claude Console under Settings › Workload identity federation.","examples":["7c9e1f3a-5b7d-4e9f-8a1c-3e5a7c9e1f3a"]},"federationRuleId":{"type":"string","pattern":"^fdrl_.*","description":"The ID of the federation rule that lets Rollstack act as `serviceAccountId`. Create it in the Claude Console under Settings › Workload identity federation, once Rollstack's issuer is added there: set its subject to your organization's (see `auth`), add a claim condition that the audience (`aud`) is `https://api.anthropic.com`, and enable it only in `workspaceId`. Starts with `fdrl_`.","examples":["fdrl_01example"]},"serviceAccountId":{"type":"string","pattern":"^svac_.*","description":"The ID of the service account Rollstack acts as in your Anthropic organization, created in the Claude Console in the workspace the slides agent should use (`workspaceId`). Starts with `svac_`.","examples":["svac_01example"]},"workspaceId":{"type":"string","pattern":"^wrkspc_.*","description":"The ID of the Claude Console workspace the slides agent's calls run in: the workspace of `serviceAccountId`, where the federation rule is enabled. Starts with `wrkspc_`.","examples":["wrkspc_01example"]}},"required":["auth","anthropicOrganizationId","federationRuleId","serviceAccountId","workspaceId"]}],"description":"How Rollstack signs in to your Anthropic organization: with an API key (`apiKey`), or without a key, through Anthropic's workload identity federation (`oidc`)."}},"required":["type","credentials"]},{"type":"object","properties":{"type":{"type":"string","const":"openai","description":"Runs the slides agent on your own OpenAI project, through the OpenAI API, with GPT-6.1 Sol (`gpt-6.1-sol`) for its main work and GPT-6 Luna (`gpt-6-luna`) for its quick steps. There are no models to pick or deploy."},"credentials":{"oneOf":[{"type":"object","properties":{"dataResidency":{"type":"string","enum":["global","us","eu"],"description":"The data residency of the OpenAI project Rollstack uses, which decides the OpenAI host Rollstack calls: `global` for OpenAI's global host, `us` or `eu` for its US or EU host. With `global`, the slides agent's web searches also run on your OpenAI project. With `us` or `eu`, they run on Rollstack's OpenAI account instead, so saving turns web search off, unless the organization's provider was already OpenAI with `us` or `eu`; an owner can turn it back on in the app."},"auth":{"type":"string","const":"apiKey","description":"Rollstack signs in to the provider with a secret you send in this request: an API key or, on Google Vertex AI, a service account key (`clientEmail` and `privateKey`). Rollstack saves the secret and never returns it, so to change it, send the whole setup again."},"apiKey":{"type":"string","minLength":1,"description":"An API key for the OpenAI project Rollstack uses, created on the OpenAI platform. The project must allow `gpt-6.1-sol` and `gpt-6-luna`, the models the slides agent runs on, in Project settings › Limits › Model usage. You can also give the project a monthly budget. Rollstack never returns the key.","examples":["your-openai-api-key"]}},"required":["dataResidency","auth","apiKey"]},{"type":"object","properties":{"dataResidency":{"type":"string","enum":["global","us","eu"],"description":"The data residency of the OpenAI project Rollstack uses, which decides the OpenAI host Rollstack calls: `global` for OpenAI's global host, `us` or `eu` for its US or EU host. With `global`, the slides agent's web searches also run on your OpenAI project. With `us` or `eu`, they run on Rollstack's OpenAI account instead, so saving turns web search off, unless the organization's provider was already OpenAI with `us` or `eu`; an owner can turn it back on in the app."},"auth":{"type":"string","const":"oidc","description":"Rollstack signs in without a saved secret: its OpenID Connect issuer signs a short-lived token for the subject `rollstack:org:<id>`, where `<id>` is your organization's `id` from `getOrganization`, and your provider exchanges the token for temporary credentials. Set up your provider to trust that issuer and to check that subject, so it accepts only your organization: `setLLMProvider` fails if the setup also accepts another organization's token. The AI provider setting in the app, under Settings › Features, shows the issuer, subject and audience to trust."},"identityProviderId":{"type":"string","minLength":1,"description":"The ID of the identity provider you create on the OpenAI platform, under Settings › Security › Workload Identity Provider, with Rollstack's issuer and the audience `https://api.openai.com`. Map it to the service account in `serviceAccountId`, with `sub` set to your organization's subject (see `auth`) and `aud` to that audience.","examples":["idp_example"]},"serviceAccountId":{"type":"string","minLength":1,"description":"The User ID of the OpenAI service account Rollstack acts as. Create the service account with Restricted permissions and Model capabilities set to Write, in a project with the data residency in `dataResidency` that allows `gpt-6.1-sol` and `gpt-6-luna`.","examples":["user-example"]}},"required":["dataResidency","auth","identityProviderId","serviceAccountId"]}],"description":"Your OpenAI project's data residency, and how Rollstack signs in to the project: with an API key (`apiKey`), or without a key, through an OpenAI workload identity provider (`oidc`)."}},"required":["type","credentials"]},{"type":"object","properties":{"type":{"type":"string","const":"azure_foundry","description":"Runs the slides agent on Claude or GPT models deployed in your Azure AI Foundry resource, the ones you pick in `credentials.models`."},"credentials":{"oneOf":[{"type":"object","properties":{"resourceName":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,62}$","description":"The name of your Azure AI Foundry resource, which Rollstack calls at `https://<resourceName>.services.ai.azure.com`. It's the first part of the host in any deployment's Target URI, such as `acme-ai` in `https://acme-ai.services.ai.azure.com`. 2 to 63 lowercase letters, digits and hyphens, starting with a letter or digit.","examples":["acme-ai"]},"models":{"type":"object","properties":{"smart":{"type":"string","enum":["claude-opus-5-5","gpt-6.1-sol"],"description":"The model that runs the slides agent and does its main work, such as editing slides and writing queries: `claude-opus-5-5` (Claude Opus 5.5) or `gpt-6.1-sol` (GPT-6.1 Sol)."},"fast":{"description":"The model for the slides agent's quick steps around its main work, such as naming the chat and inspecting slides, to save cost: `claude-haiku-5-5` (Claude Haiku 5.5) or `gpt-6-luna` (GPT-6 Luna). It can be from a different family than `smart`. If omitted, the `smart` model runs these steps too.","type":"string","enum":["claude-haiku-5-5","gpt-6-luna"]}},"required":["smart"],"description":"The models the slides agent runs on: `smart` for its main work, `fast` for its quick steps. Make them available first: on Azure AI Foundry, deploy each under its model's name (Foundry's default), such as `claude-opus-5-5`; on Amazon Bedrock, enable them in Model access in `region`."},"auth":{"type":"string","const":"apiKey","description":"Rollstack signs in to the provider with a secret you send in this request: an API key or, on Google Vertex AI, a service account key (`clientEmail` and `privateKey`). Rollstack saves the secret and never returns it, so to change it, send the whole setup again."},"apiKey":{"type":"string","minLength":1,"description":"An API key of your Azure AI Foundry resource. Rollstack uses it for every model it calls on the resource, Claude and GPT alike, and never returns it.","examples":["your-azure-api-key"]}},"required":["resourceName","models","auth","apiKey"]},{"type":"object","properties":{"resourceName":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,62}$","description":"The name of your Azure AI Foundry resource, which Rollstack calls at `https://<resourceName>.services.ai.azure.com`. It's the first part of the host in any deployment's Target URI, such as `acme-ai` in `https://acme-ai.services.ai.azure.com`. 2 to 63 lowercase letters, digits and hyphens, starting with a letter or digit.","examples":["acme-ai"]},"models":{"type":"object","properties":{"smart":{"type":"string","enum":["claude-opus-5-5","gpt-6.1-sol"],"description":"The model that runs the slides agent and does its main work, such as editing slides and writing queries: `claude-opus-5-5` (Claude Opus 5.5) or `gpt-6.1-sol` (GPT-6.1 Sol)."},"fast":{"description":"The model for the slides agent's quick steps around its main work, such as naming the chat and inspecting slides, to save cost: `claude-haiku-5-5` (Claude Haiku 5.5) or `gpt-6-luna` (GPT-6 Luna). It can be from a different family than `smart`. If omitted, the `smart` model runs these steps too.","type":"string","enum":["claude-haiku-5-5","gpt-6-luna"]}},"required":["smart"],"description":"The models the slides agent runs on: `smart` for its main work, `fast` for its quick steps. Make them available first: on Azure AI Foundry, deploy each under its model's name (Foundry's default), such as `claude-opus-5-5`; on Amazon Bedrock, enable them in Model access in `region`."},"auth":{"type":"string","const":"oidc","description":"Rollstack signs in without a saved secret: its OpenID Connect issuer signs a short-lived token for the subject `rollstack:org:<id>`, where `<id>` is your organization's `id` from `getOrganization`, and your provider exchanges the token for temporary credentials. Set up your provider to trust that issuer and to check that subject, so it accepts only your organization: `setLLMProvider` fails if the setup also accepts another organization's token. The AI provider setting in the app, under Settings › Features, shows the issuer, subject and audience to trust."},"tenantId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$","description":"The Directory (tenant) ID of your Microsoft Entra ID tenant, where you register the app Rollstack signs in as.","examples":["4d6f8a0c-2e3a-4b5c-8d7e-9f1a3b5c7d9e"]},"clientId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$","description":"The Application (client) ID of the app you register for Rollstack in Microsoft Entra ID, with no client secret. Give it a federated credential that trusts Rollstack's issuer for your organization's subject (see `auth`), with the audience `api://AzureADTokenExchange`, and the Cognitive Services User role on the resource. A new trust can take a few minutes to apply.","examples":["2b4d6f8a-0c1e-4a3b-9d5f-7b9d1f3a5c7e"]}},"required":["resourceName","models","auth","tenantId","clientId"]}],"description":"Your Azure AI Foundry resource, the models on it the slides agent runs on, and how Rollstack signs in: with the resource's API key (`apiKey`), or without a key, as an app registered in Microsoft Entra ID (`oidc`)."}},"required":["type","credentials"]},{"type":"object","properties":{"type":{"type":"string","const":"amazon_bedrock","description":"Runs the slides agent on Claude or GPT models in Amazon Bedrock, in your AWS account, the ones you pick in `credentials.models`."},"credentials":{"oneOf":[{"type":"object","properties":{"region":{"type":"string","pattern":"^[a-z]{2}(-[a-z]+)+-\\d$","description":"The AWS region Rollstack calls Amazon Bedrock in, such as `us-east-1`. It must be in `dataLocation`: a `us-` region for `us`, an `eu-` region for `eu`, `ap-southeast-2` or `ap-southeast-4` for `au`, `ap-northeast-1` or `ap-northeast-3` for `jp`, and any region for `global`.","examples":["us-east-1"]},"dataLocation":{"type":"string","enum":["us","eu","au","jp","global"],"description":"Where Amazon Bedrock may process the slides agent's requests to Claude models: `us` (United States), `eu` (Europe), `au` (Australia), `jp` (Japan) or `global`. Rollstack calls Claude through this location's cross-region inference profile, such as `us.anthropic.claude-opus-5-5` or `global.anthropic.claude-opus-5-5`, and GPT models in `region` directly."},"models":{"type":"object","properties":{"smart":{"type":"string","enum":["claude-opus-5-5","gpt-6.1-sol"],"description":"The model that runs the slides agent and does its main work, such as editing slides and writing queries: `claude-opus-5-5` (Claude Opus 5.5) or `gpt-6.1-sol` (GPT-6.1 Sol)."},"fast":{"description":"The model for the slides agent's quick steps around its main work, such as naming the chat and inspecting slides, to save cost: `claude-haiku-5-5` (Claude Haiku 5.5) or `gpt-6-luna` (GPT-6 Luna). It can be from a different family than `smart`. If omitted, the `smart` model runs these steps too.","type":"string","enum":["claude-haiku-5-5","gpt-6-luna"]}},"required":["smart"],"description":"The models the slides agent runs on: `smart` for its main work, `fast` for its quick steps. Make them available first: on Azure AI Foundry, deploy each under its model's name (Foundry's default), such as `claude-opus-5-5`; on Amazon Bedrock, enable them in Model access in `region`."},"auth":{"type":"string","const":"apiKey","description":"Rollstack signs in to the provider with a secret you send in this request: an API key or, on Google Vertex AI, a service account key (`clientEmail` and `privateKey`). Rollstack saves the secret and never returns it, so to change it, send the whole setup again."},"apiKey":{"type":"string","minLength":1,"description":"A long-term Amazon Bedrock API key, created with an expiry for an IAM user whose policy allows only the models in `models`; the AI provider setting in the app shows that policy. Rollstack uses it for Claude and GPT models alike, and never returns it.","examples":["your-bedrock-api-key"]}},"required":["region","dataLocation","models","auth","apiKey"]},{"type":"object","properties":{"region":{"type":"string","pattern":"^[a-z]{2}(-[a-z]+)+-\\d$","description":"The AWS region Rollstack calls Amazon Bedrock in, such as `us-east-1`. It must be in `dataLocation`: a `us-` region for `us`, an `eu-` region for `eu`, `ap-southeast-2` or `ap-southeast-4` for `au`, `ap-northeast-1` or `ap-northeast-3` for `jp`, and any region for `global`.","examples":["us-east-1"]},"dataLocation":{"type":"string","enum":["us","eu","au","jp","global"],"description":"Where Amazon Bedrock may process the slides agent's requests to Claude models: `us` (United States), `eu` (Europe), `au` (Australia), `jp` (Japan) or `global`. Rollstack calls Claude through this location's cross-region inference profile, such as `us.anthropic.claude-opus-5-5` or `global.anthropic.claude-opus-5-5`, and GPT models in `region` directly."},"models":{"type":"object","properties":{"smart":{"type":"string","enum":["claude-opus-5-5","gpt-6.1-sol"],"description":"The model that runs the slides agent and does its main work, such as editing slides and writing queries: `claude-opus-5-5` (Claude Opus 5.5) or `gpt-6.1-sol` (GPT-6.1 Sol)."},"fast":{"description":"The model for the slides agent's quick steps around its main work, such as naming the chat and inspecting slides, to save cost: `claude-haiku-5-5` (Claude Haiku 5.5) or `gpt-6-luna` (GPT-6 Luna). It can be from a different family than `smart`. If omitted, the `smart` model runs these steps too.","type":"string","enum":["claude-haiku-5-5","gpt-6-luna"]}},"required":["smart"],"description":"The models the slides agent runs on: `smart` for its main work, `fast` for its quick steps. Make them available first: on Azure AI Foundry, deploy each under its model's name (Foundry's default), such as `claude-opus-5-5`; on Amazon Bedrock, enable them in Model access in `region`."},"auth":{"type":"string","const":"oidc","description":"Rollstack signs in without a saved secret: its OpenID Connect issuer signs a short-lived token for the subject `rollstack:org:<id>`, where `<id>` is your organization's `id` from `getOrganization`, and your provider exchanges the token for temporary credentials. Set up your provider to trust that issuer and to check that subject, so it accepts only your organization: `setLLMProvider` fails if the setup also accepts another organization's token. The AI provider setting in the app, under Settings › Features, shows the issuer, subject and audience to trust."},"roleArn":{"type":"string","pattern":"^arn:aws:iam::\\d{12}:role\\/[\\w+=,.@/-]+$","description":"The ARN of the IAM role Rollstack assumes to call Amazon Bedrock. Its trust policy must trust Rollstack's issuer, added as an OIDC provider in your AWS account, for your organization's subject (see `auth`) and the audience `sts.amazonaws.com`. Its permissions should allow only the models in `models`. The AI provider setting in the app gives the AWS CLI commands.","examples":["arn:aws:iam::123456789012:role/rollstack-agent"]}},"required":["region","dataLocation","models","auth","roleArn"]}],"description":"Where Rollstack calls Amazon Bedrock, the models the slides agent runs on, and how Rollstack signs in: with a Bedrock API key (`apiKey`), or without a key, by assuming an IAM role (`oidc`)."}},"required":["type","credentials"]},{"type":"object","properties":{"type":{"type":"string","const":"google_vertex_ai","description":"Runs the slides agent on Claude models in Vertex AI, in your Google Cloud project: Claude Opus 5.5 for its main work and, if you add it in `credentials.models`, Claude Haiku 5.5 for its quick steps."},"credentials":{"oneOf":[{"type":"object","properties":{"projectId":{"type":"string","pattern":"^[a-z][a-z0-9-]{4,28}[a-z0-9]$","description":"The ID of the Google Cloud project Rollstack calls Vertex AI in, where you enable the models in Model Garden. Use the project ID, such as `acme-ai`, not its name or number.","examples":["acme-ai"]},"region":{"type":"string","enum":["global","us","eu"],"description":"Where Vertex AI processes the slides agent's requests: `global` (Vertex AI's global endpoint), `us` (the US multi-region) or `eu` (the EU multi-region)."},"models":{"type":"object","properties":{"smart":{"type":"string","const":"claude-opus-5-5","description":"The model that runs the slides agent and does its main work, such as editing slides and writing queries. Always `claude-opus-5-5` (Claude Opus 5.5): on Google Vertex AI, the slides agent runs on Claude only."},"fast":{"description":"The model for the slides agent's quick steps around its main work, such as naming the chat and inspecting slides, to save cost: `claude-haiku-5-5` (Claude Haiku 5.5). If omitted, `claude-opus-5-5` runs these steps too.","type":"string","const":"claude-haiku-5-5"}},"required":["smart"],"description":"The Claude models the slides agent runs on: `smart` for its main work, `fast` for its quick steps. Enable them in Vertex AI's Model Garden for `projectId`."},"auth":{"type":"string","const":"apiKey","description":"Rollstack signs in to the provider with a secret you send in this request: an API key or, on Google Vertex AI, a service account key (`clientEmail` and `privateKey`). Rollstack saves the secret and never returns it, so to change it, send the whole setup again."},"clientEmail":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","description":"The email of the Google Cloud service account Rollstack signs in as: `client_email` in its JSON key. The service account needs the Vertex AI User role.","examples":["rollstack@acme-ai.iam.gserviceaccount.com"]},"privateKey":{"type":"string","minLength":1,"description":"The service account's private key: `private_key` in its JSON key. Rollstack keeps only this and `clientEmail` from the key, and never returns the private key.","examples":["your-private-key"]}},"required":["projectId","region","models","auth","clientEmail","privateKey"]},{"type":"object","properties":{"projectId":{"type":"string","pattern":"^[a-z][a-z0-9-]{4,28}[a-z0-9]$","description":"The ID of the Google Cloud project Rollstack calls Vertex AI in, where you enable the models in Model Garden. Use the project ID, such as `acme-ai`, not its name or number.","examples":["acme-ai"]},"region":{"type":"string","enum":["global","us","eu"],"description":"Where Vertex AI processes the slides agent's requests: `global` (Vertex AI's global endpoint), `us` (the US multi-region) or `eu` (the EU multi-region)."},"models":{"type":"object","properties":{"smart":{"type":"string","const":"claude-opus-5-5","description":"The model that runs the slides agent and does its main work, such as editing slides and writing queries. Always `claude-opus-5-5` (Claude Opus 5.5): on Google Vertex AI, the slides agent runs on Claude only."},"fast":{"description":"The model for the slides agent's quick steps around its main work, such as naming the chat and inspecting slides, to save cost: `claude-haiku-5-5` (Claude Haiku 5.5). If omitted, `claude-opus-5-5` runs these steps too.","type":"string","const":"claude-haiku-5-5"}},"required":["smart"],"description":"The Claude models the slides agent runs on: `smart` for its main work, `fast` for its quick steps. Enable them in Vertex AI's Model Garden for `projectId`."},"auth":{"type":"string","const":"oidc","description":"Rollstack signs in without a saved secret: its OpenID Connect issuer signs a short-lived token for the subject `rollstack:org:<id>`, where `<id>` is your organization's `id` from `getOrganization`, and your provider exchanges the token for temporary credentials. Set up your provider to trust that issuer and to check that subject, so it accepts only your organization: `setLLMProvider` fails if the setup also accepts another organization's token. The AI provider setting in the app, under Settings › Features, shows the issuer, subject and audience to trust."},"poolProjectNumber":{"type":"string","pattern":"^\\d+$","description":"The number of the Google Cloud project that contains the workload identity pool, as `gcloud projects describe` prints it. Digits only: the project number, not its ID.","examples":["123456789012"]},"poolId":{"type":"string","pattern":"^[a-z0-9-]{4,32}$","description":"The ID of the workload identity pool that contains the provider in `providerId`, such as `rollstack`.","examples":["rollstack"]},"providerId":{"type":"string","pattern":"^[a-z0-9-]{4,32}$","description":"The ID of the OIDC provider in the pool that trusts Rollstack's issuer, such as `rollstack`. Map `google.subject` to `assertion.sub`, and keep Google's default audience, the provider's own resource name, which is the audience Rollstack's token carries. Grant the Vertex AI User role only to your organization's subject (see `auth`) in the pool.","examples":["rollstack"]}},"required":["projectId","region","models","auth","poolProjectNumber","poolId","providerId"]}],"description":"Your Google Cloud project and Vertex AI location, the models the slides agent runs on, and how Rollstack signs in: with a service account's JSON key (`apiKey`), or without a key, through workload identity federation (`oidc`)."}},"required":["type","credentials"]}]}}}},"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteLLMProvider","summary":"Delete LLM provider","description":"Deletes the organization's custom LLM provider, on any plan. Only owners, and admins an owner allowed to manage the AI provider, may call it: members' keys can't carry organization:write. Every owner gets an email.\n\nRequires the `organization:write` scope.","tags":["LLM provider"],"x-scope":"organization:write","security":[{"apiKey":[]},{"oauth2":["organization:write"]}],"parameters":[],"responses":{"204":{"description":"Success, no content"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}