# A2A Agent Source: https://docs.getalai.com/api/a2a Let other AI agents edit Alai presentations using the Agent2Agent (A2A) protocol. The **Alai A2A Agent** lets external agents drive Alai presentations through the [Agent2Agent (A2A) protocol](https://a2a-protocol.org/) — an open standard (originally from Google, now stewarded by the [a2aproject](https://github.com/a2aproject)) that lets one agent call another over HTTP+JSON with first-class support for long-running tasks, streaming, and human-in-the-loop pauses. Use A2A when your own agent (or product) needs to *delegate* presentation editing work to the Alai Agent and get back a structured task lifecycle, not just a one-shot REST response. **A2A URL:** `https://alai-standalone-backend.getalai.com/a2a` The A2A endpoint is in **beta**. The Alai Agent currently exposes a single skill — `manage_presentation` — that edits an **existing** presentation. To create a presentation from scratch, use the [REST `/generations` endpoint](/api/generations) or [MCP](/api/mcp), then hand the `presentation_id` to the Alai Agent for follow-up edits. *** ## When to use A2A vs MCP vs REST Your **autonomous agent** needs to delegate work to the Alai Agent and handle a task lifecycle (streaming updates, mid-task questions, retries). Standardised protocol, agent-to-agent. A **human-driven AI editor** (Claude, Cursor, VS Code, ChatGPT) needs Alai tools wired into its tool palette via OAuth. A **traditional backend or script** needs straight HTTP request/response with API key auth. *** ## Authentication A2A uses the same API keys as the REST API (`sk_…`). Pass them as a Bearer token: ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` If you don't have a key yet, see [Get Your API Key](/api/introduction#get-your-api-key). The `api-key` header is also accepted as a fallback for clients that can't set `Authorization`. All A2A requests must be authenticated. Unauthenticated requests return `401 Unauthorized` — the only exception is the public agent card discovery path under `/.well-known/`. *** ## Agent Card Discovery Every A2A server publishes an **Agent Card** describing its identity, capabilities, supported protocols, skills, and security requirements. Standard-compliant A2A clients fetch this card first and then route requests according to its contents. ```bash theme={null} curl https://alai-standalone-backend.getalai.com/a2a/.well-known/agent-card.json ``` Example response (abridged): ```json theme={null} { "name": "Alai Agent", "description": "Edits existing Alai presentations.", "version": "1.0.0", "supported_interfaces": [ { "protocol_binding": "HTTP+JSON", "protocol_version": "1.0", "url": "https://alai-standalone-backend.getalai.com/a2a" } ], "default_input_modes": ["text/plain", "application/json"], "default_output_modes": ["text/plain", "application/json"], "capabilities": { "streaming": true, "push_notifications": false }, "skills": [ { "id": "manage_presentation", "name": "Manage Presentation", "description": "Edit presentations -- modify slide content, layout, themes and structure. Include `presentation_id` (required) in a DataPart.", "tags": ["alai", "presentation", "slides", "editing"] } ], "security_schemes": { "Bearer": { "http_auth_security_scheme": { "scheme": "bearer", "description": "Alai API key (sk_...)." } } } } ``` If you're using the official [`a2a-sdk`](https://pypi.org/project/a2a-sdk/), use `A2ACardResolver(httpx_client, base_url).get_agent_card()` instead of fetching the JSON yourself — the resolver handles content negotiation, version checks, and constructs an `AgentCard` proto for you. *** ## Quickstart A single streaming edit request looks like this on the wire. For Python, TypeScript, or other languages, use the official [`a2a-sdk`](https://pypi.org/project/a2a-sdk/), which wraps these endpoints in idiomatic clients. ```bash theme={null} curl -X POST "https://alai-standalone-backend.getalai.com/a2a/message:stream" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -H "A2A-Version: 1.0" \ -d '{ "message": { "role": "ROLE_USER", "message_id": "11111111-1111-1111-1111-111111111111", "context_id": "22222222-2222-2222-2222-222222222222", "parts": [ { "text": "Make the title on slide 3 bigger." }, { "data": { "presentation_id": "PRESENTATION_UUID" } } ] } }' ``` Reuse the same `context_id` across turns to keep the Alai Agent in the same conversation (so it has memory of earlier edits). Generate a new one when starting a fresh session. *** ## The `manage_presentation` Skill The Alai Agent currently exposes one skill that handles edits to an existing presentation. ### Required input | Part | Type | Required | Description | | ---------------------- | -------- | -------- | ----------------------------------------------------------------------------------- | | `text` | TextPart | yes | Natural-language instruction (e.g. *"Change the chart on slide 4 to a bar chart"*). | | `data.presentation_id` | DataPart | yes | UUID of an existing Alai presentation the API key has access to. | A request without `presentation_id`, or one referencing a presentation the API key cannot access, returns `400 Bad Request`. ### What the agent can do * Modify slide content, layout, themes, and structure on existing presentations * Export the presentation to PDF or PPTX (delivered as artifacts — see below) * Ask clarifying questions when an edit is ambiguous (see [Handling INPUT\_REQUIRED](#handling-input-required)) ### What the agent will not do * Create a new presentation from scratch (use [`POST /generations`](/api/generations) instead) * Return download or share URLs inside its text reply — those are always delivered as separate **Artifacts** ### Example prompts ``` Make the title on slide 3 bigger. Change the theme to dark blue. Add a chart on slide 2 showing monthly growth. Export this presentation as a PDF. Replace the bullet points on slide 5 with a 2x2 grid. ``` *** ## Task Lifecycle Every request creates a **Task**. A2A clients stream task state transitions and any artifacts emitted along the way. | State | Meaning | | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `TASK_STATE_SUBMITTED` | Request accepted, queued for execution. | | `TASK_STATE_WORKING` | The Alai Agent is processing the request. The `presentation_url` artifact is emitted on entry. | | `TASK_STATE_INPUT_REQUIRED` | The Alai Agent needs a clarifying answer before it can continue. The task is paused — see [below](#handling-input-required). | | `TASK_STATE_COMPLETED` | Edits applied successfully; the final reply text is in the terminal status message. | | `TASK_STATE_FAILED` | The request could not be completed. The status message contains a brief reason. | | `TASK_STATE_CANCELED` | The task was cancelled via `POST /tasks/{id}:cancel`. | A typical happy-path sequence: ```mermaid theme={null} sequenceDiagram participant Client as Your Agent participant Agent as Alai Agent Client->>Agent: POST /message:stream (text + presentation_id) Agent-->>Client: status_update: SUBMITTED Agent-->>Client: status_update: WORKING Agent-->>Client: artifact: presentation_url Agent-->>Client: status_update: COMPLETED + final text ``` *** ## Handling `INPUT_REQUIRED` When the Alai Agent needs more information to fulfill a request (e.g. you said *"change the chart"* but didn't say to what), the task transitions to `TASK_STATE_INPUT_REQUIRED`. The status message contains the question(s) for you or your upstream user to answer. To resume, send a new message **with the same `context_id` and the same `task_id`**. The agent will treat your reply as the answer to the pending question and continue from where it left off. ```python theme={null} # After receiving INPUT_REQUIRED on `task_id`, send the answer: reply = Message( role=Role.ROLE_USER, message_id=str(uuid.uuid4()), parts=[ Part(text="Use a bar chart with monthly data."), Part(data=ParseDict({"presentation_id": PRESENTATION_ID}, Value())), ], context_id=context_id, # SAME context as original turn task_id=current_task_id, # SAME task to resume it ) async for event in client.send_message(SendMessageRequest(message=reply)): ... ``` Any partial edits made before the question was raised are preserved, so resuming doesn't undo prior work. *** ## Artifacts Artifacts are first-class outputs the agent attaches to a task. The Alai Agent emits up to three: | Artifact name | Emitted when | Part shape | | ------------------ | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | `presentation_url` | Always — emitted as soon as the task enters `WORKING`. Contains the live editor link. | `url` part with `media_type: text/html` | | `pdf_export` | You ask for a PDF export and it finishes successfully. | `url` part with `media_type: application/pdf` and a `filename` | | `ppt_export` | You ask for a PowerPoint export and it finishes successfully. | `url` part with `media_type: application/vnd.openxmlformats-officedocument.presentationml.presentation` and a `filename` | Example artifact event: ```json theme={null} { "artifact_update": { "artifact": { "name": "pdf_export", "parts": [ { "url": "https://signed-export-url...", "media_type": "application/pdf", "filename": "presentation.pdf" } ] } } } ``` Exports are generated asynchronously and may take up to a few minutes for large presentations. If an export does not complete within that window, the task still finishes and the agent's reply will explain that the export is still in progress. *** ## HTTP Endpoints Alai's A2A server exposes the standard set of REST endpoints defined by the protocol. Most integrations should use the official [`a2a-sdk`](https://pypi.org/project/a2a-sdk/) rather than calling these directly, but they're listed here for reference and `curl`-based testing. | Method | Path | Purpose | | ------ | ------------------------------ | ----------------------------------------------------------------------------------- | | `GET` | `/.well-known/agent-card.json` | Fetch the public agent card (no auth required). | | `POST` | `/message:send` | Send a message and wait for the final task. | | `POST` | `/message:stream` | Send a message and stream task events as they happen (recommended). | | `GET` | `/tasks/{id}` | Fetch the current state of a task. | | `POST` | `/tasks/{id}:cancel` | Cancel an in-flight task. | | `POST` | `/tasks/{id}:subscribe` | Re-attach to an in-flight task's event stream after disconnect. | | `GET` | `/tasks` | List recent tasks (filterable by `context_id`, `status`, `status_timestamp_after`). | All endpoints except agent-card discovery require `Authorization: Bearer YOUR_API_KEY`. The wire format follows the [A2A protocol v1.0 specification](https://a2a-protocol.org/v1.0.0/specification/). *** ## Error Responses | Code | Reason | | ----- | ------------------------------------------------------------------------------------------------------ | | `400` | Invalid request — typically a missing `presentation_id` or a `presentation_id` your key cannot access. | | `401` | Missing or invalid bearer token. | | `500` | An unexpected error occurred. | Failures that happen *after* a task has started surface as `TASK_STATE_FAILED` on the task itself, not as HTTP errors — by that point the request has already been accepted, so the failure lives in the task lifecycle. *** ## Next Steps A2A only edits existing presentations — start with the REST `/generations` endpoint or MCP. Human-driven AI editors (Claude, Cursor, VS Code, ChatGPT) — different protocol, different use case. # Create Slide Source: https://docs.getalai.com/api/create-slide POST /api/v1/presentations/{presentation_id}/slides Add a new slide to an existing presentation. This is an async operation—poll the returned `generation_id` for completion. The slide content will be transformed into a professionally designed slide with AI-generated layout and optional images. Add a slide to an existing presentation. This is an **async operation** - poll the returned `generation_id` for completion. ## Path Parameters | Parameter | Type | Description | | ----------------- | ------ | ------------------------------------------ | | `presentation_id` | string | ID of the presentation to add the slide to | *** ## Request Body | Parameter | Type | Default | Description | | ---------------------------------- | ------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `slide_context` | string | (required) | Content for this slide | | `options.additional_instructions` | string | - | Extra instructions for slide generation | | `options.slide_type` | string | `"classic"` | Slide style: `classic` for structured, editable text-led slides, or `creative` for image-led slides generated with Nano Banana Pro. | | `options.slide_order` | integer | (end) | Position in presentation (0-indexed) | | `options.total_variants_per_slide` | integer | 1 | Variants to generate (1-4) | | `export_formats` | array | `["link"]` | Formats to export: `link`, `pdf`, `ppt` | *** ## Response ```json theme={null} { "generation_id": "abc123-def456-..." } ``` Poll `GET /generations/{generation_id}` until status is `completed`. The response will include `slide_id`. *** ## Example ```bash theme={null} curl -X POST "https://slides-api.getalai.com/api/v1/presentations/xyz789-.../slides" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "slide_context": "Key achievements: 25% revenue growth, 50 new clients", "options": { "additional_instructions": "Make it visual with icons" } }' ``` ### Creative (Image-Led) Slide ```bash theme={null} curl -X POST "https://slides-api.getalai.com/api/v1/presentations/xyz789-.../slides" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "slide_context": "Hero shot of our new product against a sunset backdrop", "options": { "slide_type": "creative" } }' ``` *** ## Status Response When polling, the status response includes `slide_id`: ```json theme={null} { "generation_id": "abc123-...", "generation_type": "slide_creation", "status": "completed", "presentation_id": "xyz789-...", "slide_id": "slide123-...", "formats": { "link": { "status": "completed", "url": "https://app.getalai.com/view/..." } } } ``` # Delete Presentation Source: https://docs.getalai.com/api/delete-presentation DELETE /api/v1/presentations/{presentation_id} Delete a presentation and all its slides. This is a synchronous operation. ## Path Parameters | Parameter | Type | Description | | ----------------- | ------ | -------------------------------- | | `presentation_id` | string | ID of the presentation to delete | *** ## Response ```json theme={null} { "success": true, "presentation_id": "xyz789-..." } ``` *** ## Example ```bash theme={null} curl -X DELETE "https://slides-api.getalai.com/api/v1/presentations/xyz789-..." \ -H "Authorization: Bearer YOUR_API_KEY" ``` *** ## Error Responses | Status | Description | | ------ | --------------------------------------- | | 401 | Invalid or missing API key | | 404 | Presentation not found or access denied | This permanently deletes the presentation and all its slides. This action cannot be undone. # Delete Slide Source: https://docs.getalai.com/api/delete-slide DELETE /api/v1/presentations/{presentation_id}/slides/{slide_id} Delete a slide from a presentation. This is a synchronous operation. ## Path Parameters | Parameter | Type | Description | | ----------------- | ------ | ------------------------- | | `presentation_id` | string | ID of the presentation | | `slide_id` | string | ID of the slide to delete | *** ## Response ```json theme={null} { "success": true } ``` *** ## Example ```bash theme={null} curl -X DELETE "https://slides-api.getalai.com/api/v1/presentations/xyz789-.../slides/slide123-..." \ -H "Authorization: Bearer YOUR_API_KEY" ``` *** ## Error Responses | Status | Description | | ------ | ---------------------------------------- | | 400 | Slide doesn't belong to the presentation | | 401 | Invalid or missing API key | | 404 | Presentation or slide not found | This action is permanent. Deleted slides cannot be recovered. # Examples & Use Cases Source: https://docs.getalai.com/api/examples Complete Python examples and real-world use cases for the Alai API. This guide provides complete, working examples for common Alai API workflows. All examples use Python with the `requests` library. ## Installation ```bash theme={null} pip install requests ``` *** ## AlaiClient Helper Class Copy this helper class to simplify your Alai API integrations. It handles polling, error handling, and provides a clean interface for all operations. ```python theme={null} """ Alai API Python Client A simple wrapper for common Alai API operations """ import requests import time from typing import List, Optional class AlaiClient: """Simple Python client for the Alai API.""" def __init__(self, api_key: str): self.api_key = api_key self.base_url = "https://slides-api.getalai.com/api/v1" self.headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } def generate_presentation( self, content: str, title: str = "Presentation", slide_range: str = "auto", theme_id: Optional[str] = None, export_formats: List[str] = None, image_ids: List[str] = None, wait: bool = True, timeout: int = 300 ) -> dict: """ Generate a presentation from text content. Args: content: The text content to transform into slides title: Presentation title slide_range: Number of slides ("auto", "1", "2-5", "6-10", etc.) theme_id: Theme ID from get_themes(). Legacy theme display names still work but are deprecated. export_formats: List of formats ["link", "pdf", "ppt"] image_ids: List of image IDs from upload_images() wait: If True, polls until completion timeout: Max seconds to wait Returns: Generation result with presentation URLs """ if export_formats is None: export_formats = ["link"] payload = { "input_text": content, "presentation_options": { "title": title, "slide_range": slide_range }, "export_formats": export_formats } if theme_id: payload["presentation_options"]["theme_id"] = theme_id if image_ids: payload["image_ids"] = image_ids response = requests.post( f"{self.base_url}/generations", headers=self.headers, json=payload ) response.raise_for_status() result = response.json() if wait: return self.wait_for_completion(result["generation_id"], timeout) return result def get_themes(self) -> List[dict]: """ List available themes for the authenticated user. Returns: List of theme objects with `id` and `name` """ response = requests.get( f"{self.base_url}/themes", headers=self.headers ) response.raise_for_status() return response.json()["themes"] def wait_for_completion(self, generation_id: str, timeout: int = 300) -> dict: """ Poll until a generation completes or fails. Args: generation_id: The ID returned from an async operation timeout: Max seconds to wait Returns: Final generation status with results Raises: Exception: If generation fails TimeoutError: If timeout exceeded """ start = time.time() while time.time() - start < timeout: response = requests.get( f"{self.base_url}/generations/{generation_id}", headers=self.headers ) response.raise_for_status() result = response.json() if result["status"] == "completed": return result elif result["status"] == "failed": raise Exception(f"Generation failed: {result.get('error')}") time.sleep(3) raise TimeoutError(f"Generation {generation_id} timed out after {timeout}s") def add_slide( self, presentation_id: str, content: str, instructions: str = None, position: int = None, wait: bool = True ) -> dict: """ Add a slide to an existing presentation. Args: presentation_id: ID of the presentation content: Content for the new slide instructions: Additional styling instructions position: Slide position (None = append at end) wait: If True, polls until completion Returns: Generation result with slide_id """ payload = { "slide_context": content, "options": {} } if instructions: payload["options"]["additional_instructions"] = instructions if position is not None: payload["options"]["slide_order"] = position response = requests.post( f"{self.base_url}/presentations/{presentation_id}/slides", headers=self.headers, json=payload ) response.raise_for_status() result = response.json() if wait: return self.wait_for_completion(result["generation_id"]) return result def export( self, presentation_id: str, formats: List[str] = None, wait: bool = True ) -> dict: """ Export a presentation to specified formats. Args: presentation_id: ID of the presentation formats: List of formats ["link", "pdf", "ppt"] wait: If True, polls until completion Returns: Export result with download URLs """ if formats is None: formats = ["link", "pdf"] response = requests.post( f"{self.base_url}/presentations/{presentation_id}/exports", headers=self.headers, json={"formats": formats} ) response.raise_for_status() result = response.json() if wait: return self.wait_for_completion(result["generation_id"]) return result def upload_images(self, file_paths: List[str]) -> List[str]: """ Upload images for use in presentations. Args: file_paths: List of local file paths Returns: List of image IDs to use in generation requests """ files = [("files", open(path, "rb")) for path in file_paths] response = requests.post( f"{self.base_url}/upload-images", headers={"Authorization": f"Bearer {self.api_key}"}, files=files ) response.raise_for_status() return response.json()["image_ids"] def delete_presentation(self, presentation_id: str) -> bool: """Delete a presentation.""" response = requests.delete( f"{self.base_url}/presentations/{presentation_id}", headers=self.headers ) response.raise_for_status() return response.json().get("success", False) def delete_slide(self, presentation_id: str, slide_id: str) -> bool: """Delete a slide from a presentation.""" response = requests.delete( f"{self.base_url}/presentations/{presentation_id}/slides/{slide_id}", headers=self.headers ) response.raise_for_status() return response.json().get("success", False) ``` Save this as `alai_client.py` and import it in your projects: `from alai_client import AlaiClient` *** ## Example 1: Generate a Simple Presentation The most basic use case - turn text into a presentation. ```python theme={null} from alai_client import AlaiClient client = AlaiClient("your_api_key") theme_id = client.get_themes()[0]["id"] # Generate a presentation from text result = client.generate_presentation( content=""" Introduction to Machine Learning Machine learning is a subset of artificial intelligence that enables systems to learn and improve from experience without being explicitly programmed. Key concepts: - Supervised Learning: Learning from labeled data - Unsupervised Learning: Finding patterns in unlabeled data - Reinforcement Learning: Learning through trial and error Applications include image recognition, natural language processing, recommendation systems, and autonomous vehicles. """, title="Introduction to Machine Learning", slide_range="6-10", theme_id=theme_id, export_formats=["link", "pdf"] ) print(f"View online: {result['formats']['link']['url']}") print(f"Download PDF: {result['formats']['pdf']['url']}") ``` *** ## Example 2: Weekly Report Generator Automate recurring presentations like weekly reports. ```python theme={null} from alai_client import AlaiClient from datetime import datetime client = AlaiClient("your_api_key") default_theme_id = client.get_themes()[0]["id"] def generate_weekly_report(metrics: dict) -> dict: """Generate a weekly report presentation from metrics.""" week_num = datetime.now().isocalendar()[1] year = datetime.now().year content = f""" Weekly Business Report - Week {week_num}, {year} Revenue Performance: - Total Revenue: ${metrics['revenue']:,.0f} - Week-over-Week Change: {metrics['revenue_change']:+.1f}% - Year-to-Date: ${metrics['ytd_revenue']:,.0f} Customer Metrics: - New Customers: {metrics['new_customers']} - Churn Rate: {metrics['churn_rate']:.1f}% - Net Promoter Score: {metrics['nps']} Top Products: 1. {metrics['top_products'][0]['name']} - ${metrics['top_products'][0]['revenue']:,.0f} 2. {metrics['top_products'][1]['name']} - ${metrics['top_products'][1]['revenue']:,.0f} 3. {metrics['top_products'][2]['name']} - ${metrics['top_products'][2]['revenue']:,.0f} Key Highlights: {chr(10).join(f"- {h}" for h in metrics['highlights'])} Challenges & Action Items: {chr(10).join(f"- {c}" for c in metrics['challenges'])} """ return client.generate_presentation( content=content, title=f"Weekly Report - W{week_num}", slide_range="6-10", theme_id=default_theme_id, export_formats=["link", "pdf", "ppt"] ) # Example usage metrics = { "revenue": 1_250_000, "revenue_change": 15.3, "ytd_revenue": 45_000_000, "new_customers": 47, "churn_rate": 2.1, "nps": 72, "top_products": [ {"name": "Enterprise Plan", "revenue": 450_000}, {"name": "Team Plan", "revenue": 380_000}, {"name": "Starter Plan", "revenue": 370_000} ], "highlights": [ "Closed 3 enterprise deals worth $500K+", "Product launch exceeded expectations by 40%", "Customer satisfaction at all-time high" ], "challenges": [ "APAC region underperforming targets", "Support ticket volume up 20%" ] } result = generate_weekly_report(metrics) print(f"Report ready: {result['formats']['link']['url']}") ``` *** ## Example 3: Document to Slides Convert meeting notes, documents, or any text file into a presentation. ```python theme={null} from alai_client import AlaiClient client = AlaiClient("your_api_key") # Read content from a file with open("meeting_notes.txt", "r") as f: notes = f.read() # Generate presentation result = client.generate_presentation( content=notes, title="Product Roadmap Review - Q1 Planning", slide_range="11-15", export_formats=["link", "ppt"] ) print(f"Presentation: {result['formats']['link']['url']}") print(f"PowerPoint: {result['formats']['ppt']['url']}") ``` The API automatically structures your content into logical slides. For best results, use clear headings and bullet points in your source text. *** ## Example 4: Add Slides to Existing Presentation Build presentations incrementally by adding slides one at a time. ```python theme={null} from alai_client import AlaiClient client = AlaiClient("your_api_key") # First, create a base presentation result = client.generate_presentation( content="Company Overview: Founded in 2020, we build AI-powered tools.", title="Company Overview", slide_range="2-5" ) presentation_id = result["presentation_id"] print(f"Created presentation: {presentation_id}") # Add a new slide with team information team_result = client.add_slide( presentation_id=presentation_id, content=""" Our Team: - 50+ engineers across 3 continents - Leadership from Google, Meta, and Amazon - 60% of team has advanced degrees """, instructions="Use a team-focused layout with icons" ) print(f"Added team slide: {team_result['slide_id']}") # Add another slide with metrics metrics_result = client.add_slide( presentation_id=presentation_id, content=""" Key Metrics: - $10M ARR - 500+ enterprise customers - 99.9% uptime - 4.8/5 customer rating """, instructions="Make it visually impactful with large numbers" ) print(f"Added metrics slide: {metrics_result['slide_id']}") # Export the final presentation export = client.export(presentation_id, formats=["link", "pdf", "ppt"]) print(f"Final presentation: {export['formats']['link']['url']}") ``` *** ## Example 5: Batch Processing Generate multiple presentations efficiently. ```python theme={null} from alai_client import AlaiClient from concurrent.futures import ThreadPoolExecutor client = AlaiClient("your_api_key") # Define multiple presentations to generate presentations = [ { "title": "Q1 Financial Results", "content": "Q1 revenue: $5M, growth: 25%, new customers: 150..." }, { "title": "Q2 Financial Results", "content": "Q2 revenue: $6.2M, growth: 24%, new customers: 180..." }, { "title": "Q3 Financial Results", "content": "Q3 revenue: $7.5M, growth: 21%, new customers: 200..." }, { "title": "Q4 Financial Results", "content": "Q4 revenue: $9M, growth: 20%, new customers: 250..." } ] def generate_one(spec): """Generate a single presentation.""" result = client.generate_presentation( content=spec["content"], title=spec["title"], slide_range="6-10", export_formats=["link", "pdf"] ) return { "title": spec["title"], "url": result["formats"]["link"]["url"], "pdf": result["formats"]["pdf"]["url"] } # Process sequentially (recommended to stay within rate limits) results = [] for spec in presentations: print(f"Generating: {spec['title']}...") result = generate_one(spec) results.append(result) print(f" Done: {result['url']}") # Print summary print("\n=== All Presentations ===") for r in results: print(f"{r['title']}: {r['url']}") ``` Respect the rate limit of 5 concurrent generations. For large batches, process sequentially or add delays between requests. *** ## Example 6: Presentations with Custom Images Upload your own images to include in presentations. ```python theme={null} from alai_client import AlaiClient client = AlaiClient("your_api_key") # Upload images first image_ids = client.upload_images([ "product_screenshot.png", "team_photo.jpg", "office_building.png" ]) print(f"Uploaded {len(image_ids)} images: {image_ids}") # Generate presentation referencing uploaded images via their IDs result = client.generate_presentation( content=""" About Our Company Our Product: A revolutionary AI-powered analytics platform that helps businesses make data-driven decisions in real-time. Our Team: A diverse group of engineers, designers, and business experts united by a passion for innovation. Our Office: Located in the heart of San Francisco, our modern workspace fosters creativity and collaboration. """, title="About Our Company", slide_range="6-10", image_ids=image_ids ) print(f"Presentation: {result['formats']['link']['url']}") ``` Supported image formats: PNG, JPEG, WebP, GIF, AVIF, SVG. Max 10MB per file, 10 images per upload. *** ## Error Handling Best Practices Robust error handling for production use. ```python theme={null} from alai_client import AlaiClient import requests import time client = AlaiClient("your_api_key") def generate_with_retry(content: str, title: str, max_retries: int = 3) -> dict: """Generate a presentation with automatic retry on failure.""" for attempt in range(max_retries): try: result = client.generate_presentation( content=content, title=title, export_formats=["link"] ) return result except requests.exceptions.HTTPError as e: status_code = e.response.status_code if status_code == 401: raise Exception("Invalid API key. Check your credentials.") elif status_code == 402: raise Exception("Insufficient credits. Please top up your account.") elif status_code == 429: # Rate limited - wait and retry wait_time = 2 ** attempt * 5 # Exponential backoff print(f"Rate limited. Waiting {wait_time}s before retry...") time.sleep(wait_time) continue elif status_code >= 500: # Server error - retry wait_time = 2 ** attempt * 2 print(f"Server error. Waiting {wait_time}s before retry...") time.sleep(wait_time) continue else: raise except TimeoutError: if attempt < max_retries - 1: print(f"Timeout. Retrying... ({attempt + 1}/{max_retries})") continue raise except Exception as e: print(f"Unexpected error: {e}") raise raise Exception(f"Failed after {max_retries} attempts") # Usage try: result = generate_with_retry( content="Your presentation content...", title="My Presentation" ) print(f"Success: {result['formats']['link']['url']}") except Exception as e: print(f"Failed: {e}") ``` *** ## Next Steps Detailed documentation for all endpoints and parameters Discover theme IDs and names available to your account # Export Presentation Source: https://docs.getalai.com/api/export-presentation POST /api/v1/presentations/{presentation_id}/exports Export an existing presentation to one or more formats (PDF, PPTX). This is an async operation. Poll `GET /generations/{generation_id}` until status is `completed`, then access download URLs in the `formats` field. Export an existing presentation to PDF, PPT, or get a shareable link. This is an **async operation**. ## Path Parameters | Parameter | Type | Description | | ----------------- | ------ | -------------------------------- | | `presentation_id` | string | ID of the presentation to export | *** ## Request Body | Parameter | Type | Default | Description | | --------- | ----- | ---------- | --------------------------------------- | | `formats` | array | `["link"]` | Formats to export: `link`, `pdf`, `ppt` | *** ## Response ```json theme={null} { "generation_id": "abc123-def456-..." } ``` Poll `GET /generations/{generation_id}` until status is `completed`. *** ## Example ### Export to Multiple Formats ```bash theme={null} curl -X POST "https://slides-api.getalai.com/api/v1/presentations/xyz789-.../exports" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "formats": ["link", "pdf", "ppt"] }' ``` ### Status Response ```json theme={null} { "generation_id": "abc123-...", "generation_type": "presentation_export", "status": "completed", "presentation_id": "xyz789-...", "formats": { "link": { "status": "completed", "url": "https://app.getalai.com/view/..." }, "pdf": { "status": "completed", "url": "https://storage.../presentation.pdf" }, "ppt": { "status": "completed", "url": "https://storage.../presentation.pptx" } } } ``` Download URLs are signed and valid for 24 hours. Download promptly or call this endpoint again to get fresh URLs. # Extract Transcripts Source: https://docs.getalai.com/api/generate-transcripts POST /api/v1/presentations/{presentation_id}/transcripts Extract slide content and layout information using AI. This is an async operation. Returns a structured description of each slide's text content and layout. You can process all slides or specify particular slide IDs. Extract structured content and layout information from slides. This is an **async operation**. ## Path Parameters | Parameter | Type | Description | | ----------------- | ------ | ---------------------- | | `presentation_id` | string | ID of the presentation | *** ## Request Body | Parameter | Type | Default | Description | | ----------- | ----- | ------------ | ----------------------------------------------------------------------------------- | | `slide_ids` | array | (all slides) | Specific slide IDs to extract transcripts for. If omitted, extracts for all slides. | *** ## Response ```json theme={null} { "generation_id": "abc123-def456-..." } ``` Poll `GET /generations/{generation_id}` until status is `completed`. *** ## Example ### All Slides ```bash theme={null} curl -X POST "https://slides-api.getalai.com/api/v1/presentations/xyz789-.../transcripts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}' ``` ### Specific Slides ```bash theme={null} curl -X POST "https://slides-api.getalai.com/api/v1/presentations/xyz789-.../transcripts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "slide_ids": ["slide1-...", "slide2-..."] }' ``` *** ## Status Response ```json theme={null} { "generation_id": "abc123-...", "generation_type": "transcript_generation", "status": "completed", "presentation_id": "xyz789-...", "transcripts": [ { "slide_id": "slide1-...", "slide_order": 0, "title": "Q4 Sales Report", "content": "Quarterly Performance Overview\n\nRevenue: $1.2M\nGrowth: +25% YoY", "layout": "TITLE_SLIDE" }, { "slide_id": "slide2-...", "slide_order": 1, "title": "Key Metrics", "content": "• New customers: 150\n• Retention rate: 94%\n• NPS score: 72", "layout": "CONTENT_SLIDE" } ] } ``` Transcript generation uses credits. The cost is based on the number of slides processed. # Check Generation Status Source: https://docs.getalai.com/api/generation-status GET /api/v1/generations/{generation_id} Poll this endpoint to check the status of any async operation (presentation generation, slide creation, export, or transcript generation). **Status values:** - `pending` - Queued, not yet started - `in_progress` - Currently processing - `completed` - Finished successfully; results available in response - `failed` - Error occurred; check `error` field for details **Recommended polling:** Every 2-5 seconds. Most generations complete within 30-120 seconds. Poll this endpoint to check the status of any async operation (presentation generation, slide creation, export, or transcript generation). ## Status Values | Status | Description | | ------------- | ---------------------------------------- | | `pending` | Queued, not yet started | | `in_progress` | Currently processing | | `completed` | Finished successfully; results available | | `failed` | Error occurred; check `error` field | **Recommended polling:** Every 5 seconds. Most operations complete within 1-3 minutes depending on slide count. *** ## Response Fields | Field | Type | Description | | ----------------- | ------ | --------------------------------- | | `generation_id` | string | The generation ID you're polling | | `status` | string | Current status | | `error` | string | Error message (when `failed`) | | `created_at` | string | ISO 8601 timestamp | | `completed_at` | string | When generation finished | | `presentation_id` | string | ID of the presentation | | `formats` | object | Export results (when `completed`) | *** ## Format Results When status is `completed`, the `formats` object contains results for each requested format: ```json theme={null} { "generation_id": "abc123-...", "status": "completed", "presentation_id": "xyz789-...", "formats": { "link": { "status": "completed", "url": "https://app.getalai.com/view/..." }, "pdf": { "status": "completed", "url": "https://storage.../presentation.pdf" }, "ppt": { "status": "completed", "url": "https://storage.../presentation.pptx" } } } ``` Each format has: * `status`: `completed`, `failed`, or `skipped` * `url`: Signed download URL (valid for 24 hours) * `error`: Error message if failed *** ## Example ```bash theme={null} curl "https://slides-api.getalai.com/api/v1/generations/abc123-def456-..." \ -H "Authorization: Bearer YOUR_API_KEY" ``` *** ## Polling Example (Python) ```python theme={null} import time import requests def wait_for_generation(generation_id, api_key, max_wait=300): url = f"https://slides-api.getalai.com/api/v1/generations/{generation_id}" headers = {"Authorization": f"Bearer {api_key}"} start = time.time() while time.time() - start < max_wait: response = requests.get(url, headers=headers) data = response.json() if data["status"] == "completed": return data elif data["status"] == "failed": raise Exception(data.get("error", "Generation failed")) time.sleep(3) # Poll every 3 seconds raise TimeoutError("Generation timed out") # Usage result = wait_for_generation("abc123-...", "YOUR_API_KEY") print(result["formats"]["link"]["url"]) ``` Download URLs in the `formats` object are signed and valid for 24 hours. Store the `presentation_id` if you need to export again later. # Generate Presentation Source: https://docs.getalai.com/api/generations POST /api/v1/generations Create a new presentation from text content. This is an async operation. **Workflow:** 1. Submit your content and options 2. Receive a `generation_id` immediately 3. Poll `GET /generations/{generation_id}` until status is `completed` or `failed` 4. Access your presentation via the URLs in the response **Rate limit:** Max 5 concurrent generations per user. Generate a presentation from text content. This is an **async operation** - you receive a `generation_id` immediately and poll for results. ## Workflow 1. **Submit** your content with `POST /generations` 2. **Receive** a `generation_id` immediately 3. **Poll** `GET /generations/{generation_id}` until `status` is `completed` or `failed` 4. **Access** your presentation via URLs in the `formats` field *** ## Request Body ### Required | Parameter | Type | Description | | ------------ | ------ | ----------------------------------------------------------------------------------- | | `input_text` | string | Content to transform into slides. Can be plain text, markdown, or structured notes. | ### Optional Top-Level Fields | Parameter | Type | Description | | ------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------- | | `additional_instructions` | string | Extra guidance for the AI on style, focus areas, or specific requirements not captured by other options. | | `image_ids` | array of strings | IDs (UUIDs) of previously uploaded images from `POST /upload-images`. Images are matched to relevant slides automatically. | ### Export Formats | Parameter | Type | Default | Description | | ---------------- | ----- | ---------- | -------------------------------------------------------------- | | `export_formats` | array | `["link"]` | Formats to export: `link`, `pdf`, `ppt`. Can request multiple. | ### Presentation Options | Parameter | Type | Default | Description | | ----------------------------------------------- | ------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `presentation_options.title` | string | "API Generated Presentation" | Title shown on title slide and in exports | | `presentation_options.theme_id` | string | `"27874e6b-8c1c-4301-bce7-d22e6e8df7d6"` | Theme ID controlling colors, fonts, and styling. Use `GET /themes` to discover available theme IDs. Legacy theme display names are still accepted for backward compatibility, but deprecated. | | `presentation_options.slide_range` | string | "auto" | Target slide count: `auto`, `1`, `2-5`, `6-10`, `11-15`, `16-20`, `21-25`, `26-50` | | `presentation_options.existing_presentation_id` | string | - | Append slides to existing presentation | | `presentation_options.total_variants_per_slide` | integer | 1 | Variants per slide (1-4) | | `presentation_options.vibe_id` | string | - | Vibe ID controlling the visual aesthetic of creative variants. Use `GET /vibes` to discover available vibe IDs. Requires `image_options.num_image_variants >= 1` when set. If omitted, standard theme styling is used. | ### Text Options | Parameter | Type | Default | Description | | ----------------------- | ------ | ------- | --------------- | | `text_options.language` | string | (auto) | Output language | ### Image Options | Parameter | Type | Default | Description | | ---------------------------------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `image_options.include_ai_images` | boolean | true | Generate AI images | | `image_options.include_web_images` | boolean | true | Search the web for relevant images to include in slides | | `image_options.style` | string | "auto" | Image style: `auto`, `realistic`, `artistic`, `cartoon`, `three_d`, `custom` | | `image_options.style_instructions` | string | - | Required when style is `custom` | | `image_options.num_image_variants` | integer | 0 | Number of creative image-led slide variants generated using Nano Banana Pro (0-2). Required (>=1) when `presentation_options.vibe_id` is set. Increases cost. | *** ## Response ```json theme={null} { "generation_id": "abc123-def456-789..." } ``` Use this `generation_id` to poll `GET /generations/{generation_id}` for status. *** ## Examples ### Basic Generation ```bash theme={null} curl -X POST "https://slides-api.getalai.com/api/v1/generations" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input_text": "Our company achieved 25% revenue growth this quarter." }' ``` ### With Multiple Export Formats ```bash theme={null} # First, discover a theme ID with GET /themes curl -X POST "https://slides-api.getalai.com/api/v1/generations" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input_text": "Quarterly sales report content...", "export_formats": ["link", "pdf", "ppt"], "presentation_options": { "title": "Q4 Sales Report", "theme_id": "27874e6b-8c1c-4301-bce7-d22e6e8df7d6", "slide_range": "6-10" }, }' ``` `theme_id` now primarily expects a theme ID from `GET /themes`. Legacy theme display names still work for backward compatibility, but they are deprecated. ### With a Vibe Vibes are visual aesthetic presets applied through creative image variants. Discover available vibe IDs with `GET /vibes`. ```bash theme={null} curl -X POST "https://slides-api.getalai.com/api/v1/generations" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input_text": "Launch announcement for our new product line", "presentation_options": { "title": "Product Launch", "vibe_id": "f1c2d3e4-5678-90ab-cdef-1234567890ab", "slide_range": "6-10" }, "image_options": { "num_image_variants": 1 } }' ``` When `vibe_id` is set, `image_options.num_image_variants` must be `>= 1`. Vibes are applied through creative image variants. ### Add to Existing Presentation ```bash theme={null} curl -X POST "https://slides-api.getalai.com/api/v1/generations" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input_text": "Additional slides content...", "presentation_options": { "existing_presentation_id": "xyz789-...", "slide_range": "2-5" } }' ``` Request multiple `export_formats` in a single call to get link, PDF, and PPT all at once. Check the `formats` object in the status response for download URLs. # Get Presentations Source: https://docs.getalai.com/api/get-presentations GET /api/v1/presentations Returns a list of all presentations owned by the authenticated user, including their IDs and titles. Retrieve a list of all presentations belonging to the authenticated user. Returns presentations sorted by creation date (newest first). *** ## Response | Field | Type | Description | | --------------- | ----- | ------------------------------ | | `presentations` | array | List of presentation summaries | ### Presentation Summary Each presentation in the array contains: | Field | Type | Description | | ------- | ------ | -------------------------------------- | | `id` | string | Unique identifier for the presentation | | `title` | string | Title of the presentation | *** ## Example Response ```json theme={null} { "presentations": [ { "id": "abc123-def456-789", "title": "Q4 Sales Report" }, { "id": "xyz789-abc123-456", "title": "Product Roadmap 2025" } ] } ``` *** ## Example Request ```bash theme={null} curl -X GET "https://slides-api.getalai.com/api/v1/presentations" \ -H "Authorization: Bearer YOUR_API_KEY" ``` Use the `id` from this response to perform operations like adding slides, exporting, or deleting presentations. # Get Themes Source: https://docs.getalai.com/api/get-themes GET /api/v1/themes Returns theme IDs and names for all system themes and user themes accessible to the authenticated user. Retrieve the themes available to the authenticated user. This endpoint returns both system themes and any user themes you can access. Use the returned `id` values as `presentation_options.theme_id` when generating presentations. `theme_id` now primarily expects a theme ID from this endpoint. Legacy theme display names are still accepted for backward compatibility, but they are deprecated. *** ## Response | Field | Type | Description | | -------- | ----- | -------------------------------------------------- | | `themes` | array | List of themes available to the authenticated user | ### Theme Object | Field | Type | Description | | ------ | ------ | ------------------------------------------------------------------ | | `id` | string | Unique theme identifier to pass as `presentation_options.theme_id` | | `name` | string | Human-readable theme display name | *** ## Example Request ```bash theme={null} curl -X GET "https://slides-api.getalai.com/api/v1/themes" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "themes": [ { "id": "27874e6b-8c1c-4301-bce7-d22e6e8df7d6", "name": "Simple Light" } ] } ``` *** ## Using a Theme ID in Presentation Generation ```bash theme={null} curl -X POST "https://slides-api.getalai.com/api/v1/generations" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input_text": "Quarterly business review content...", "presentation_options": { "title": "QBR", "theme_id": "27874e6b-8c1c-4301-bce7-d22e6e8df7d6", "slide_range": "6-10" } }' ``` # Get Vibes Source: https://docs.getalai.com/api/get-vibes GET /api/v1/vibes Returns vibe IDs and names for all system vibes and custom user vibes accessible to the authenticated user. Pass the `id` as `presentation_options.vibe_id` on a generation request. Retrieve the vibes available to the authenticated user. A **vibe** is a visual aesthetic preset (mood, palette, illustration style) that gets applied to creative slide variants. This endpoint returns both system vibes and any custom vibes you have created. Use the returned `id` values as `presentation_options.vibe_id` when generating presentations. Vibes are applied through creative image variants. When you pass `vibe_id`, you must also set `image_options.num_image_variants >= 1` on the generation request. *** ## Response | Field | Type | Description | | ------- | ----- | ------------------------------------------------- | | `vibes` | array | List of vibes available to the authenticated user | ### Vibe Object | Field | Type | Description | | -------- | ------ | ---------------------------------------------------------------- | | `id` | string | Unique vibe identifier to pass as `presentation_options.vibe_id` | | `name` | string | Human-readable vibe display name | | `source` | string | Either `system` (built-in) or `custom` (created by the user) | *** ## Example Request ```bash theme={null} curl -X GET "https://slides-api.getalai.com/api/v1/vibes" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "vibes": [ { "id": "b8e3a9ae-f36c-458b-a816-acd5f43072d3", "name": "Standard", "source": "system" }, { "id": "f1c2d3e4-5678-90ab-cdef-1234567890ab", "name": "Neon Dreams", "source": "system" }, { "id": "a1b2c3d4-5678-90ab-cdef-fedcba987654", "name": "My Brand Vibe", "source": "custom" } ] } ``` *** ## Using a Vibe ID in Presentation Generation ```bash theme={null} curl -X POST "https://slides-api.getalai.com/api/v1/generations" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input_text": "Launch announcement for our new product line", "presentation_options": { "title": "Product Launch", "vibe_id": "f1c2d3e4-5678-90ab-cdef-1234567890ab", "slide_range": "6-10" }, "image_options": { "num_image_variants": 1 } }' ``` # Getting Started Source: https://docs.getalai.com/api/introduction Build AI-powered presentation generation into your applications with the Alai API. [Alai](https://www.getalai.com) transforms how teams create presentations. Instead of spending hours in PowerPoint, describe what you need and get professionally designed slides in seconds. The **Alai API** brings this power to your applications. Generate presentations programmatically, integrate with your workflows, and automate slide creation at scale. We also support the [Model Context Protocol (MCP)](/api/mcp) for seamless integration with MCP clients like Claude, Cursor, and VS Code, and the [Agent2Agent (A2A) protocol](/api/a2a) for autonomous agents that need to delegate presentation editing to Alai. API Introduction *** ## What You Can Build Turn text, notes, or documents into complete slide decks with AI-powered design Programmatically add new slides to existing presentations Get shareable links, PDFs, or PowerPoint files Get structured content and layout information from slides *** ## How It Works Sign up at [app.getalai.com](https://app.getalai.com) and generate an API key from your account settings. POST to `/generations` with your text content. You'll receive a `generation_id` immediately. Check `GET /generations/{id}` every few seconds until status is `completed`. Get shareable links, download PDFs, or export to PowerPoint from the response. *** ## Quick Example ```python Python theme={null} import requests import time API_KEY = "your_api_key" BASE_URL = "https://slides-api.getalai.com/api/v1" # 1. Generate presentation response = requests.post( f"{BASE_URL}/generations", headers={"Authorization": f"Bearer {API_KEY}"}, json={ "input_text": "Q4 revenue grew 25%. Key wins: Enterprise deals and product launches.", "presentation_options": {"title": "Q4 Results", "slide_range": "6-10"}, "export_formats": ["link", "pdf"] } ) generation_id = response.json()["generation_id"] # 2. Poll until complete while True: status = requests.get( f"{BASE_URL}/generations/{generation_id}", headers={"Authorization": f"Bearer {API_KEY}"} ).json() if status["status"] == "completed": print(f"View: {status['formats']['link']['url']}") print(f"PDF: {status['formats']['pdf']['url']}") break elif status["status"] == "failed": raise Exception(status.get("error")) time.sleep(3) ``` ```bash cURL theme={null} # 1. Generate presentation curl -X POST "https://slides-api.getalai.com/api/v1/generations" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input_text": "Q4 revenue grew 25%. Key wins: Enterprise deals and product launches.", "presentation_options": {"title": "Q4 Results", "slide_range": "6-10"}, "export_formats": ["link", "pdf"] }' # Response: {"generation_id": "abc123-..."} # 2. Poll for status curl "https://slides-api.getalai.com/api/v1/generations/abc123-..." \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```javascript JavaScript theme={null} const API_KEY = "your_api_key"; const BASE_URL = "https://slides-api.getalai.com/api/v1"; // 1. Generate presentation const response = await fetch(`${BASE_URL}/generations`, { method: "POST", headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ input_text: "Q4 revenue grew 25%. Key wins: Enterprise deals and product launches.", presentation_options: { title: "Q4 Results", slide_range: "6-10" }, export_formats: ["link", "pdf"] }) }); const { generation_id } = await response.json(); // 2. Poll until complete const poll = async () => { while (true) { const res = await fetch(`${BASE_URL}/generations/${generation_id}`, { headers: { "Authorization": `Bearer ${API_KEY}` } }); const status = await res.json(); if (status.status === "completed") { console.log("View:", status.formats.link.url); console.log("PDF:", status.formats.pdf.url); return status; } else if (status.status === "failed") { throw new Error(status.error); } await new Promise(r => setTimeout(r, 3000)); } }; await poll(); ``` *** ## Get Your API Key 1. **Sign up** at [app.getalai.com](https://app.getalai.com) 2. **Click on your name** in the left sidebar 3. **Select "API"** from the dropdown menu 4. **Click "Add new API key"** to generate your key 5. **Copy and securely store** your API key Keep your API key secure and never share it publicly. Treat it like a password. *** ## Authentication All requests require a Bearer token in the `Authorization` header: ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` **Base URL:** ``` https://slides-api.getalai.com/api/v1 ``` *** ## Available Endpoints ### Async Operations These endpoints return a `generation_id`. Poll `GET /generations/{id}` until complete. | Endpoint | Method | Description | | --------------------------------- | ------ | ------------------------------------- | | `/generations` | POST | Generate a presentation from text | | `/presentations/{id}/slides` | POST | Add a slide to a presentation | | `/presentations/{id}/exports` | POST | Export to PDF, PPT, or shareable link | | `/presentations/{id}/transcripts` | POST | Extract slide content and layout | ### Synchronous Operations These endpoints return results immediately. | Endpoint | Method | Description | | --------------------------------------- | ------ | --------------------------------------------------------- | | `/ping` | GET | Verify your API key | | `/themes` | GET | List theme IDs and names available to your account | | `/vibes` | GET | List vibe IDs, names, and source for visual style presets | | `/generations/{id}` | GET | Check generation status | | `/upload-images` | POST | Upload images for presentations | | `/presentations/{id}/slides/{slide_id}` | DELETE | Delete a slide | | `/presentations/{id}` | DELETE | Delete a presentation | *** ## Generation Status When polling, you'll see one of these status values: | Status | Description | | ------------- | ------------------------------------ | | `pending` | Queued, not yet started | | `in_progress` | Currently processing | | `completed` | Finished successfully | | `failed` | Error occurred (check `error` field) | Poll every 5 seconds. Most generations complete within 1-3 minutes depending on slide count. *** ## Available Themes Use `GET /themes` to discover the theme IDs and display names available to the authenticated user, including system themes and any user themes you can access. Theme selection now primarily uses `theme_id` values returned by that endpoint. Legacy theme display names are still accepted for backward compatibility, but they are deprecated. See the [Get Themes](/api/get-themes) reference for the response format and example usage. *** ## Vibes A **vibe** is a visual aesthetic preset (mood, palette, illustration style) applied to creative slide variants. Pass `presentation_options.vibe_id` on a generation request to use one. Use `GET /vibes` to discover the vibe IDs available to your account, including system vibes and any custom vibes you have created. When `vibe_id` is set, you must also set `image_options.num_image_variants >= 1` — vibes are applied through creative image variants. See the [Get Vibes](/api/get-vibes) reference for the response format and example usage. *** ## Rate Limits * **Max 5 concurrent generations** per user * Recommended polling interval: 5 seconds Need higher rate limits? Reach out to the Alai team at [founders@getalai.com](mailto:founders@getalai.com). *** ## Credits API generations consume the same credits as the [Alai app](https://www.getalai.com). To check your balance or purchase more credits: * Go to **Settings** in your [Alai account](https://app.getalai.com) * Or contact [founders@getalai.com](mailto:founders@getalai.com) for enterprise plans *** ## Error Handling | Code | Description | | ----- | ----------------------------------------- | | `200` | Success | | `400` | Bad Request - Invalid parameters | | `401` | Unauthorized - Invalid or missing API key | | `402` | Payment Required - Insufficient credits | | `404` | Not Found - Resource doesn't exist | | `422` | Validation Error - Check request body | | `429` | Rate limit exceeded | | `500` | Internal Server Error | Error responses include details: ```json theme={null} { "message": "Error description", "status_code": 400 } ``` *** ## Next Steps Complete Python examples with a helper client class Full API reference for presentation generation Connect MCP clients like Claude and Cursor to Alai Delegate presentation editing to Alai from your own AI agent # MCP Integration Source: https://docs.getalai.com/api/mcp Connect AI agents like Claude, Cursor, and VS Code to Alai using the Model Context Protocol. The **Alai MCP Server** lets AI agents generate presentations, manage slides, and export content directly through the [Model Context Protocol](https://modelcontextprotocol.io/). Authentication is handled via OAuth — your editor opens a browser window for sign-in on first use. No API key required. **MCP URL:** `https://slides-api.getalai.com/mcp/` *** ## Getting Started Run this command in your terminal: ```bash theme={null} claude mcp add --transport http alai https://slides-api.getalai.com/mcp/ ``` Then type `/mcp` in a Claude Code session to initiate the OAuth sign-in flow. Go to **Settings** → **Connectors** and add a custom connector with this URL: ``` https://slides-api.getalai.com/mcp/ ``` Click the **+** button in the chat box, then **Connectors** to verify. Remote MCP connectors are available on Claude Pro, Max, Team, and Enterprise plans. Open **Cursor Settings** → **MCP** and add a new server, or add to `~/.cursor/mcp.json`: ```json theme={null} { "mcpServers": { "alai": { "type": "streamable-http", "url": "https://slides-api.getalai.com/mcp/" } } } ``` Requires VS Code 1.102 or later. Open the Command Palette (**Cmd/Ctrl + Shift + P**), run **MCP: Add Server**, and select **HTTP**. Use this URL: ``` https://slides-api.getalai.com/mcp/ ``` Or add it to `.vscode/mcp.json`: ```json theme={null} { "servers": { "alai": { "type": "http", "url": "https://slides-api.getalai.com/mcp/" } } } ``` Go to **Windsurf Settings** → **Manage MCPs** → **View raw config** and add: ```json theme={null} { "mcpServers": { "alai": { "serverUrl": "https://slides-api.getalai.com/mcp/" } } } ``` Go to **Settings** → **Connectors** → **Add connector** and enter: ``` https://slides-api.getalai.com/mcp/ ``` ChatGPT will open a browser window for OAuth sign-in. Custom connectors are available on ChatGPT Pro, Business, and Enterprise plans. *** ## Docs for AI Give your AI agent access to Alai's docs so it can look up API endpoints, authentication, webhooks, and more while building. For **Claude Code**, run this command in your terminal: ```bash theme={null} claude mcp add alai-docs -- uvx mcpdoc --urls "https://docs.getalai.com/llms.txt" ``` For **Claude Desktop**, **Cursor**, or **VS Code**, add an MCP server with these settings: ```json Claude Desktop & Cursor theme={null} { "mcpServers": { "alai-docs": { "command": "uvx", "args": [ "mcpdoc", "--urls", "https://docs.getalai.com/llms.txt" ] } } } ``` ```json VS Code theme={null} { "servers": { "alai-docs": { "command": "uvx", "args": [ "mcpdoc", "--urls", "https://docs.getalai.com/llms.txt" ] } } } ``` Requires [`uv`](https://docs.astral.sh/uv/) (provides `uvx`). Install with `brew install uv` or see the [installation docs](https://docs.astral.sh/uv/getting-started/installation/) for other platforms. Uses [`mcpdoc`](https://github.com/langchain-ai/mcpdoc) by LangChain. Your agent gets a search tool over all Alai documentation, powered by the auto-generated [`llms.txt`](https://docs.getalai.com/llms.txt) and [`llms-full.txt`](https://docs.getalai.com/llms-full.txt) indexes. *** ## Available Tools The Alai MCP server exposes 11 tools that map to the [Alai API](/api/introduction): | Tool | Description | | ----------------------- | ---------------------------------------------------------------------------- | | `ping` | Verify authentication and return user ID | | `get_presentations` | List all presentations for the authenticated user | | `get_themes` | List theme IDs and names available to the authenticated user | | `get_vibes` | List vibe IDs, names, and source (system or custom) for visual style presets | | `generate_presentation` | Create a presentation from text content | | `get_generation_status` | Poll async operation status | | `create_slide` | Add a slide to an existing presentation | | `delete_slide` | Remove a slide from a presentation | | `export_presentation` | Export to PDF, PPTX, or shareable link | | `generate_transcripts` | Generate speaker notes for slides | | `delete_presentation` | Permanently delete a presentation | *** ## Example Usage Once connected, ask your AI agent to create presentations: **Prompt**: "Show me the theme IDs I can use for a presentation" The AI will call `get_themes` and return the available theme IDs and display names. **Prompt**: "Create a 5-slide presentation about the benefits of remote work" The AI can call `get_themes` first to pick a theme, then `generate_presentation` and poll `get_generation_status` until complete. **Prompt**: "Add a slide about team collaboration tools to my presentation" **Prompt**: "Export my presentation as a PowerPoint file" **Prompt**: "Create speaker notes for all slides in my presentation" *** ## Authentication Authentication is handled via OAuth 2.1. On first connection, your editor opens a browser window where you sign in to Alai. Tokens refresh automatically. MCP clients discover OAuth configuration via: ``` GET https://slides-api.getalai.com/.well-known/oauth-protected-resource/mcp ``` For programmatic access (CI, scripts, direct HTTP), use the [Alai REST API](/api/introduction) with an API key instead. *** ## Workflow Presentation generation is asynchronous: ```mermaid theme={null} sequenceDiagram participant Agent as AI Agent participant MCP as Alai MCP participant API as Alai API Agent->>MCP: generate_presentation(content) MCP->>API: POST /generations API-->>MCP: generation_id MCP-->>Agent: generation_id loop Poll until complete Agent->>MCP: get_generation_status(id) MCP->>API: GET /generations/{id} API-->>MCP: status, presentation_id MCP-->>Agent: status end Agent->>MCP: export_presentation(id, format) MCP->>API: POST /exports API-->>MCP: export_url MCP-->>Agent: download link ``` Most AI agents handle polling automatically. Just describe what you want and the agent will manage the async workflow. *** ## Troubleshooting * Make sure your client supports remote MCP servers with OAuth (Claude Code, Claude Desktop, Cursor, VS Code 1.102+, ChatGPT) * Check that your firewall allows outbound HTTPS connections * Restart your MCP client after adding the server * Re-run the OAuth sign-in flow from your client's MCP settings * Make sure you're signed in to the same Alai account your presentations belong to * Some clients require a restart after adding MCP servers * Verify the server status indicator (should be green/active) * Maximum 5 concurrent generations per user * Contact [founders@getalai.com](mailto:founders@getalai.com) for higher limits *** ## Next Steps Full API documentation with all endpoints and parameters Python examples and use cases for the Alai API For autonomous agents that need to delegate edits, not human-driven editors # Upload Images Source: https://docs.getalai.com/api/upload-images POST /api/v1/upload-images Upload images to be used in presentation generation. Returns image IDs that can be referenced in subsequent requests. **Limits:** Max 10 images per request, 10MB per file. Supported formats: PNG, JPEG, WebP, GIF, AVIF, SVG. Upload images for use in presentation generation. This is a synchronous operation that returns image IDs (UUIDs) immediately. These can be passed via `image_ids` in subsequent generation requests. ## Limits * **Max file size:** 10MB per image * **Max images:** 10 per request * **Supported formats:** PNG, JPEG, WebP, GIF, AVIF, SVG *** ## Request Send images as `multipart/form-data` with field name `files`. ### curl ```bash theme={null} curl -X POST "https://slides-api.getalai.com/api/v1/upload-images" \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "files=@/path/to/image1.png" \ -F "files=@/path/to/image2.jpg" ``` ### Python ```python theme={null} import requests url = "https://slides-api.getalai.com/api/v1/upload-images" headers = {"Authorization": "Bearer YOUR_API_KEY"} files = [ ("files", ("image1.png", open("image1.png", "rb"), "image/png")), ("files", ("image2.jpg", open("image2.jpg", "rb"), "image/jpeg")), ] response = requests.post(url, headers=headers, files=files) print(response.json()) ``` ### JavaScript ```javascript theme={null} const formData = new FormData(); formData.append('files', file1); formData.append('files', file2); const response = await fetch('https://slides-api.getalai.com/api/v1/upload-images', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, body: formData }); const data = await response.json(); console.log(data.image_ids); ``` *** ## Response ```json theme={null} { "image_ids": [ "123e4567-e89b-12d3-a456-426614174000", "987fcdeb-51a2-3c4d-e5f6-789012345678" ] } ``` *** ## Error Responses | Status | Description | | ------ | --------------------------------- | | 400 | File too large or too many images | | 401 | Invalid or missing API key | | 415 | Unsupported file type |