productivity
Gmail Lua API for KosmoKrator Agents
Agent-facing Lua documentation and function reference for the Gmail KosmoKrator integration.Lua Namespace
Agents call this integration through app.integrations.gmail.*.
Use lua_read_doc("integrations.gmail") inside KosmoKrator to discover the same reference at runtime.
Call Lua from the Headless CLI
Use kosmo integrations:lua when a shell script, CI job, cron job, or another coding CLI should run a deterministic
Gmail workflow without starting an interactive agent session.
kosmo integrations:lua --eval 'dump(app.integrations.gmail.add_labels({message_id = "example_message_id", message_ids = "example_message_ids", label_ids = "example_label_ids"}))' --json kosmo integrations:lua --eval 'print(docs.read("gmail"))' --json
kosmo integrations:lua --eval 'print(docs.read("gmail.add_labels"))' --json Workflow file
Put repeatable logic in a Lua file, then execute it with JSON output for the calling process.
local gmail = app.integrations.gmail
local result = gmail.add_labels({message_id = "example_message_id", message_ids = "example_message_ids", label_ids = "example_label_ids"})
dump(result) kosmo integrations:lua workflow.lua --json
kosmo integrations:lua workflow.lua --force --json integrations:lua exposes app.integrations.gmail, app.mcp.*, docs.*, json.*, and regex.*. Use app.integrations.gmail.default.* or app.integrations.gmail.work.* when you configured named credential accounts.
MCP-only Lua
If the script only needs configured MCP servers and does not need Gmail, use the narrower mcp:lua command.
# Use mcp:lua for MCP-only scripts; use integrations:lua for this integration namespace.
kosmo mcp:lua --eval 'dump(mcp.servers())' --json Agent-Facing Lua Docs
This is the rendered version of the full Lua documentation exposed to agents when they inspect the integration namespace.
Google Integration — Lua API Supplement
Google services are registered as separate namespaces: integrations.gmail, integrations["google-sheets"], integrations["google-calendar"], integrations["google-drive"], etc. All share the same OAuth credentials.
Gmail
Send email with CC/BCC:
app.integrations.gmail.gmail_send_email({
to = "alice@example.com",
subject = "Q1 Report",
body = "Please find the report attached.",
cc = "bob@example.com, carol@example.com",
bcc = "manager@example.com",
})
Search, read, then reply workflow:
-- Step 1: Search for messages
local results = app.integrations.gmail.gmail_search_emails({
query = "from:alice subject:meeting is:unread",
max_results = 5,
})
-- Step 2: Read the full message
local msg = app.integrations.gmail.gmail_read({ message_id = results.messages[1].id })
-- Step 3: Reply in the same thread
app.integrations.gmail.gmail_reply({
message_id = msg.id,
thread_id = msg.threadId,
body = "Thanks, I'll be there.",
cc = "team@example.com",
})
Draft vs direct send — use create_draft to stage an email without sending, then send_draft to send it later:
-- Create a draft (not sent)
local draft = app.integrations.gmail.gmail_create_draft({
to = "client@example.com",
subject = "Proposal",
body = "Draft content here...",
})
-- Send it later using the draft ID
app.integrations.gmail.gmail_send_draft({ draft_id = draft.draftId })
Google Sheets
Values use 2D Lua tables — each inner table is one row:
local values = {
{"Name", "Age", "City"},
{"Alice", 30, "NYC"},
{"Bob", 25, "LA"},
}
A1 notation examples:
"Sheet1!A1:D10"— specific range"Sheet1!A:A"— entire column"Sheet1"— entire sheet"'My Sheet'!A1:B2"— sheet names with spaces need quotes
Input modes: "user_entered" (default) parses formulas and dates, "raw" stores literal strings.
Create a spreadsheet, add a sheet, write data:
-- Create a new spreadsheet
local ss = app.integrations["google-sheets"].google_sheets_create({ title = "Q1 Sales" })
local id = ss.spreadsheetId
-- Add a second sheet/tab
app.integrations["google-sheets"].google_sheets_add_sheet({
spreadsheet_id = id,
title = "By Region",
})
-- Write data with headers
app.integrations["google-sheets"].google_sheets_write_range({
spreadsheet_id = id,
range = "Sheet1!A1:C3",
values = {
{"Region", "Revenue", "Growth"},
{"North", 50000, "=B2/50000-1"},
{"South", 42000, "=B3/42000-1"},
},
input = "user_entered", -- parses the formulas
})
Read data back:
local data = app.integrations["google-sheets"].google_sheets_read_range({
spreadsheet_id = id,
range = "Sheet1!A1:C3",
render = "formatted", -- "formatted" (default), "unformatted", or "formula"
})
-- data.values is a 2D table: {{"Region","Revenue","Growth"}, {"North","50000","0%"}, ...}
Append vs write — append_rows auto-detects the last row and adds below it:
app.integrations["google-sheets"].google_sheets_append({
spreadsheet_id = id,
range = "Sheet1",
values = {
{"East", 38000, "=B4/38000-1"},
},
input = "user_entered",
})
Google Calendar
Create a timed event with attendees:
app.integrations["google-calendar"].google_calendar_create_event({
summary = "Sprint Planning",
description = "Bi-weekly sprint planning session",
location = "Conference Room B",
start_date_time = "2026-04-01T10:00:00-05:00",
end_date_time = "2026-04-01T11:00:00-05:00",
time_zone = "America/New_York",
attendees = "alice@example.com, bob@example.com",
recurrence = "RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=10",
})
Create an all-day event:
app.integrations["google-calendar"].google_calendar_create_event({
summary = "Company Holiday",
start_date = "2026-07-04",
end_date = "2026-07-05",
})
Date/time format: ISO 8601 with timezone offset for timed events (2026-04-01T10:00:00-05:00), plain YYYY-MM-DD for all-day events. Use time_zone for IANA names like "America/New_York".
Google Drive
Search for files, then get details:
-- Search by name and type
local results = app.integrations["google-drive"].google_drive_search_files({
query = "name contains 'report' and mimeType = 'application/vnd.google-apps.spreadsheet'",
max_results = 10,
order_by = "modifiedTime desc",
})
-- Get full file info (and optionally export content)
local file = app.integrations["google-drive"].google_drive_get_file({
file_id = results.files[1].id,
export_as = "csv", -- "text", "csv", or "markdown" (Google Workspace files only)
})
Common Drive query patterns:
"name contains 'budget'"— by name"mimeType = 'application/vnd.google-apps.spreadsheet'"— Sheets"mimeType = 'application/vnd.google-apps.document'"— Docs"mimeType = 'application/vnd.google-apps.folder'"— folders"modifiedTime > '2026-01-01'"— recently modified"sharedWithMe = true"— shared files"'FOLDER_ID' in parents"— files in a folder
Share a file:
-- Share with a specific user
app.integrations["google-drive"].google_drive_share_file({
file_id = "abc123",
role = "writer", -- "reader", "writer", or "commenter"
email = "alice@example.com",
notify = "true",
})
-- Share with anyone via link
app.integrations["google-drive"].google_drive_share_file({
file_id = "abc123",
role = "reader",
type = "anyone",
})
Google Analytics
The GA4 namespace is app.integrations["google-analytics"]. Start with property discovery, then run metadata or report tools against the numeric property ID.
local properties = app.integrations["google-analytics"].google_analytics_list_properties({})
Run a standard report:
local report = app.integrations["google-analytics"].google_analytics_report({
property_id = "123456789",
metrics = {"sessions", "totalUsers"},
dimensions = {"sessionDefaultChannelGroup"},
start_date = "28daysAgo",
end_date = "yesterday",
order_by = "sessions",
order_direction = "desc",
limit = 20,
})
Check compatibility before combining unfamiliar dimensions and metrics:
local compatibility = app.integrations["google-analytics"].google_analytics_check_compatibility({
property_id = "123456789",
metrics = {"sessions"},
dimensions = {"country", "deviceCategory"},
})
Run pivot and batch reports when you need the exact Google Analytics Data API response shape:
local pivot = app.integrations["google-analytics"].google_analytics_pivot_report({
property_id = "123456789",
metrics = {"sessions"},
dimensions = {"country", "deviceCategory"},
pivots = {
{ fieldNames = {"country"}, limit = 10 },
{ fieldNames = {"deviceCategory"}, limit = 5 },
},
})
local batch = app.integrations["google-analytics"].google_analytics_batch_run_reports({
property_id = "123456789",
requests = {
{
metrics = {{ name = "sessions" }},
dimensions = {{ name = "country" }},
dateRanges = {{ startDate = "7daysAgo", endDate = "yesterday" }},
},
},
})
Tips
- All Google APIs share the same OAuth token — if Gmail is connected, the same credentials work for Sheets, Drive, Calendar, etc.
- Use
input = "user_entered"when writing Sheets data that contains formulas (e.g.,"=SUM(A1:A10)") or dates. Use"raw"for literal strings. - Sheet names with spaces must be quoted in A1 notation:
"'My Sheet'!A1:B2". append_rowsis better thanwrite_rangewhen adding rows to an existing table — it auto-detects where the data ends.- Calendar event times use ISO 8601 with timezone offset. Always include the offset or set
time_zoneexplicitly. - Drive search excludes trashed files by default.
Multi-Account Usage
If you have multiple Google service accounts configured, use account-specific namespaces:
-- Default account (always works)
app.integrations["google-sheets"].function_name({...})
-- Explicit default (portable across setups)
app.integrations["google-sheets"].default.function_name({...})
-- Named accounts
app.integrations["google-sheets"].work.function_name({...})
app.integrations["google-sheets"].personal.function_name({...})
All functions are identical across accounts — only the credentials differ.
Raw agent markdown
# Google Integration — Lua API Supplement
Google services are registered as separate namespaces: `integrations.gmail`, `integrations["google-sheets"]`, `integrations["google-calendar"]`, `integrations["google-drive"]`, etc. All share the same OAuth credentials.
## Gmail
Send email with CC/BCC:
```lua
app.integrations.gmail.gmail_send_email({
to = "alice@example.com",
subject = "Q1 Report",
body = "Please find the report attached.",
cc = "bob@example.com, carol@example.com",
bcc = "manager@example.com",
})
```
Search, read, then reply workflow:
```lua
-- Step 1: Search for messages
local results = app.integrations.gmail.gmail_search_emails({
query = "from:alice subject:meeting is:unread",
max_results = 5,
})
-- Step 2: Read the full message
local msg = app.integrations.gmail.gmail_read({ message_id = results.messages[1].id })
-- Step 3: Reply in the same thread
app.integrations.gmail.gmail_reply({
message_id = msg.id,
thread_id = msg.threadId,
body = "Thanks, I'll be there.",
cc = "team@example.com",
})
```
Draft vs direct send -- use `create_draft` to stage an email without sending, then `send_draft` to send it later:
```lua
-- Create a draft (not sent)
local draft = app.integrations.gmail.gmail_create_draft({
to = "client@example.com",
subject = "Proposal",
body = "Draft content here...",
})
-- Send it later using the draft ID
app.integrations.gmail.gmail_send_draft({ draft_id = draft.draftId })
```
## Google Sheets
Values use 2D Lua tables -- each inner table is one row:
```lua
local values = {
{"Name", "Age", "City"},
{"Alice", 30, "NYC"},
{"Bob", 25, "LA"},
}
```
A1 notation examples:
- `"Sheet1!A1:D10"` -- specific range
- `"Sheet1!A:A"` -- entire column
- `"Sheet1"` -- entire sheet
- `"'My Sheet'!A1:B2"` -- sheet names with spaces need quotes
Input modes: `"user_entered"` (default) parses formulas and dates, `"raw"` stores literal strings.
Create a spreadsheet, add a sheet, write data:
```lua
-- Create a new spreadsheet
local ss = app.integrations["google-sheets"].google_sheets_create({ title = "Q1 Sales" })
local id = ss.spreadsheetId
-- Add a second sheet/tab
app.integrations["google-sheets"].google_sheets_add_sheet({
spreadsheet_id = id,
title = "By Region",
})
-- Write data with headers
app.integrations["google-sheets"].google_sheets_write_range({
spreadsheet_id = id,
range = "Sheet1!A1:C3",
values = {
{"Region", "Revenue", "Growth"},
{"North", 50000, "=B2/50000-1"},
{"South", 42000, "=B3/42000-1"},
},
input = "user_entered", -- parses the formulas
})
```
Read data back:
```lua
local data = app.integrations["google-sheets"].google_sheets_read_range({
spreadsheet_id = id,
range = "Sheet1!A1:C3",
render = "formatted", -- "formatted" (default), "unformatted", or "formula"
})
-- data.values is a 2D table: {{"Region","Revenue","Growth"}, {"North","50000","0%"}, ...}
```
Append vs write -- `append_rows` auto-detects the last row and adds below it:
```lua
app.integrations["google-sheets"].google_sheets_append({
spreadsheet_id = id,
range = "Sheet1",
values = {
{"East", 38000, "=B4/38000-1"},
},
input = "user_entered",
})
```
## Google Calendar
Create a timed event with attendees:
```lua
app.integrations["google-calendar"].google_calendar_create_event({
summary = "Sprint Planning",
description = "Bi-weekly sprint planning session",
location = "Conference Room B",
start_date_time = "2026-04-01T10:00:00-05:00",
end_date_time = "2026-04-01T11:00:00-05:00",
time_zone = "America/New_York",
attendees = "alice@example.com, bob@example.com",
recurrence = "RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=10",
})
```
Create an all-day event:
```lua
app.integrations["google-calendar"].google_calendar_create_event({
summary = "Company Holiday",
start_date = "2026-07-04",
end_date = "2026-07-05",
})
```
Date/time format: ISO 8601 with timezone offset for timed events (`2026-04-01T10:00:00-05:00`), plain `YYYY-MM-DD` for all-day events. Use `time_zone` for IANA names like `"America/New_York"`.
## Google Drive
Search for files, then get details:
```lua
-- Search by name and type
local results = app.integrations["google-drive"].google_drive_search_files({
query = "name contains 'report' and mimeType = 'application/vnd.google-apps.spreadsheet'",
max_results = 10,
order_by = "modifiedTime desc",
})
-- Get full file info (and optionally export content)
local file = app.integrations["google-drive"].google_drive_get_file({
file_id = results.files[1].id,
export_as = "csv", -- "text", "csv", or "markdown" (Google Workspace files only)
})
```
Common Drive query patterns:
- `"name contains 'budget'"` -- by name
- `"mimeType = 'application/vnd.google-apps.spreadsheet'"` -- Sheets
- `"mimeType = 'application/vnd.google-apps.document'"` -- Docs
- `"mimeType = 'application/vnd.google-apps.folder'"` -- folders
- `"modifiedTime > '2026-01-01'"` -- recently modified
- `"sharedWithMe = true"` -- shared files
- `"'FOLDER_ID' in parents"` -- files in a folder
Share a file:
```lua
-- Share with a specific user
app.integrations["google-drive"].google_drive_share_file({
file_id = "abc123",
role = "writer", -- "reader", "writer", or "commenter"
email = "alice@example.com",
notify = "true",
})
-- Share with anyone via link
app.integrations["google-drive"].google_drive_share_file({
file_id = "abc123",
role = "reader",
type = "anyone",
})
```
## Google Analytics
The GA4 namespace is `app.integrations["google-analytics"]`. Start with property discovery, then run metadata or report tools against the numeric property ID.
```lua
local properties = app.integrations["google-analytics"].google_analytics_list_properties({})
```
Run a standard report:
```lua
local report = app.integrations["google-analytics"].google_analytics_report({
property_id = "123456789",
metrics = {"sessions", "totalUsers"},
dimensions = {"sessionDefaultChannelGroup"},
start_date = "28daysAgo",
end_date = "yesterday",
order_by = "sessions",
order_direction = "desc",
limit = 20,
})
```
Check compatibility before combining unfamiliar dimensions and metrics:
```lua
local compatibility = app.integrations["google-analytics"].google_analytics_check_compatibility({
property_id = "123456789",
metrics = {"sessions"},
dimensions = {"country", "deviceCategory"},
})
```
Run pivot and batch reports when you need the exact Google Analytics Data API response shape:
```lua
local pivot = app.integrations["google-analytics"].google_analytics_pivot_report({
property_id = "123456789",
metrics = {"sessions"},
dimensions = {"country", "deviceCategory"},
pivots = {
{ fieldNames = {"country"}, limit = 10 },
{ fieldNames = {"deviceCategory"}, limit = 5 },
},
})
local batch = app.integrations["google-analytics"].google_analytics_batch_run_reports({
property_id = "123456789",
requests = {
{
metrics = {{ name = "sessions" }},
dimensions = {{ name = "country" }},
dateRanges = {{ startDate = "7daysAgo", endDate = "yesterday" }},
},
},
})
```
## Tips
- All Google APIs share the same OAuth token -- if Gmail is connected, the same credentials work for Sheets, Drive, Calendar, etc.
- Use `input = "user_entered"` when writing Sheets data that contains formulas (e.g., `"=SUM(A1:A10)"`) or dates. Use `"raw"` for literal strings.
- Sheet names with spaces must be quoted in A1 notation: `"'My Sheet'!A1:B2"`.
- `append_rows` is better than `write_range` when adding rows to an existing table -- it auto-detects where the data ends.
- Calendar event times use ISO 8601 with timezone offset. Always include the offset or set `time_zone` explicitly.
- Drive search excludes trashed files by default.
---
## Multi-Account Usage
If you have multiple Google service accounts configured, use account-specific namespaces:
```lua
-- Default account (always works)
app.integrations["google-sheets"].function_name({...})
-- Explicit default (portable across setups)
app.integrations["google-sheets"].default.function_name({...})
-- Named accounts
app.integrations["google-sheets"].work.function_name({...})
app.integrations["google-sheets"].personal.function_name({...})
```
All functions are identical across accounts — only the credentials differ. local result = app.integrations.gmail.add_labels({message_id = "example_message_id", message_ids = "example_message_ids", label_ids = "example_label_ids"})
print(result) Functions
add_labels Write
Add labels to one or more Gmail messages. Provide messageIds (comma-separated) for batch operations.
- Lua path
app.integrations.gmail.add_labels- Full name
gmail.gmail_add_labels
| Parameter | Type | Required | Description |
|---|---|---|---|
message_id | string | no | Single message ID to add labels to. |
message_ids | string | no | Comma-separated message IDs for batch operations. |
label_ids | string | yes | Comma-separated label IDs to add. |
archive Read
Archive one or more Gmail messages (remove from inbox). Provide messageIds (comma-separated) for batch operations.
- Lua path
app.integrations.gmail.archive- Full name
gmail.gmail_archive
| Parameter | Type | Required | Description |
|---|---|---|---|
message_id | string | no | Single message ID to archive. |
message_ids | string | no | Comma-separated message IDs for batch operations. |
create_draft Write
Create a draft email in Gmail (not sent).
- Lua path
app.integrations.gmail.create_draft- Full name
gmail.gmail_create_draft
| Parameter | Type | Required | Description |
|---|---|---|---|
to | string | yes | Recipient email address. |
subject | string | yes | Email subject. |
body | string | no | Email body text. |
cc | string | no | CC recipients (comma-separated emails). |
bcc | string | no | BCC recipients (comma-separated emails). |
mark_read Write
Mark one or more Gmail messages as read. Provide messageIds (comma-separated) for batch operations.
- Lua path
app.integrations.gmail.mark_read- Full name
gmail.gmail_mark_read
| Parameter | Type | Required | Description |
|---|---|---|---|
message_id | string | no | Single message ID to mark as read. |
message_ids | string | no | Comma-separated message IDs for batch operations. |
mark_unread Write
Mark one or more Gmail messages as unread. Provide messageIds (comma-separated) for batch operations.
- Lua path
app.integrations.gmail.mark_unread- Full name
gmail.gmail_mark_unread
| Parameter | Type | Required | Description |
|---|---|---|---|
message_id | string | no | Single message ID to mark as unread. |
message_ids | string | no | Comma-separated message IDs for batch operations. |
read Read
Read the full content of a Gmail message by its ID. Returns headers (From, To, Subject, Date), the decoded text body, and a list of attachments. Use gmail_search first to find message IDs, then use this tool to read the full content.
- Lua path
app.integrations.gmail.read- Full name
gmail.gmail_read
| Parameter | Type | Required | Description |
|---|---|---|---|
message_id | string | yes | Gmail message ID to read. |
format | string | no | Response format: "full" (default, includes body), "metadata" (headers only), "minimal" (IDs only). |
remove_labels Write
Remove labels from one or more Gmail messages. Provide messageIds (comma-separated) for batch operations.
- Lua path
app.integrations.gmail.remove_labels- Full name
gmail.gmail_remove_labels
| Parameter | Type | Required | Description |
|---|---|---|---|
message_id | string | no | Single message ID to remove labels from. |
message_ids | string | no | Comma-separated message IDs for batch operations. |
label_ids | string | yes | Comma-separated label IDs to remove. |
reply Read
Reply to an existing Gmail message (maintains the thread).
- Lua path
app.integrations.gmail.reply- Full name
gmail.gmail_reply
| Parameter | Type | Required | Description |
|---|---|---|---|
message_id | string | yes | Original message ID to reply to. |
thread_id | string | yes | Thread ID to reply in. |
body | string | yes | Reply body text. |
to | string | no | Recipient email address (defaults to original sender). |
cc | string | no | CC recipients (comma-separated emails). |
bcc | string | no | BCC recipients (comma-separated emails). |
count_by_sender Read
Count all matching Gmail messages grouped by sender. Automatically paginates through ALL results (handles thousands of messages). Returns top senders sorted by count. Use for questions like "who sends me the most email?" or "count unread by sender".
- Lua path
app.integrations.gmail.count_by_sender- Full name
gmail.gmail_count_by_sender
| Parameter | Type | Required | Description |
|---|---|---|---|
query | string | no | Gmail search query to filter messages (e.g., "is:unread", "after:2026-01-01"). |
label_ids | string | no | Comma-separated label IDs to filter by. |
list_labels Read
List all labels in the Gmail mailbox (INBOX, SENT, custom labels, etc.).
- Lua path
app.integrations.gmail.list_labels- Full name
gmail.gmail_list_labels
| Parameter | Type | Required | Description |
|---|---|---|---|
| No parameters. | |||
save_attachment Read
Download an email attachment and save it to workspace files. Requires a messageId and attachmentId (both returned by gmail_read). The file is saved under the agent's folder and can be browsed in the Files page.
- Lua path
app.integrations.gmail.save_attachment- Full name
gmail.gmail_save_attachment
| Parameter | Type | Required | Description |
|---|---|---|---|
message_id | string | yes | Gmail message ID containing the attachment. |
attachment_id | string | yes | Attachment ID from the gmail_read response. |
filename | string | yes | Filename to save as (e.g. "invoice.pdf"). Use the filename from gmail_read. |
mime_type | string | no | MIME type of the attachment (e.g. "application/pdf"). Use the mimeType from gmail_read. |
search_emails Read
Search Gmail messages using Gmail query syntax (e.g., "from:alice subject:meeting is:unread has:attachment after:2026-02-01"). Returns message summaries with headers. Max 100 per page.
- Lua path
app.integrations.gmail.search_emails- Full name
gmail.gmail_search_emails
| Parameter | Type | Required | Description |
|---|---|---|---|
query | string | no | Gmail search query (e.g., "from:alice subject:meeting is:unread"). |
max_results | integer | no | Max results to return (default: 10, max: 100). |
page_token | string | no | Pagination token from previous response. |
label_ids | string | no | Comma-separated label IDs to filter by. |
send_draft Write
Send a previously created Gmail draft by its ID.
- Lua path
app.integrations.gmail.send_draft- Full name
gmail.gmail_send_draft
| Parameter | Type | Required | Description |
|---|---|---|---|
draft_id | string | yes | Draft ID to send. |
send_email Write
Send an email directly via Gmail.
- Lua path
app.integrations.gmail.send_email- Full name
gmail.gmail_send_email
| Parameter | Type | Required | Description |
|---|---|---|---|
to | string | yes | Recipient email address. |
subject | string | yes | Email subject. |
body | string | yes | Email body text. |
cc | string | no | CC recipients (comma-separated emails). |
bcc | string | no | BCC recipients (comma-separated emails). |
trash Read
Move one or more Gmail messages to trash. Provide messageIds (comma-separated) for batch operations.
- Lua path
app.integrations.gmail.trash- Full name
gmail.gmail_trash
| Parameter | Type | Required | Description |
|---|---|---|---|
message_id | string | no | Single message ID to trash. |
message_ids | string | no | Comma-separated message IDs for batch operations. |
untrash Read
Remove one or more Gmail messages from trash. Provide messageIds (comma-separated) for batch operations.
- Lua path
app.integrations.gmail.untrash- Full name
gmail.gmail_untrash
| Parameter | Type | Required | Description |
|---|---|---|---|
message_id | string | no | Single message ID to restore from trash. |
message_ids | string | no | Comma-separated message IDs for batch operations. |