miro-api
Miro whiteboard automation using REST API v2 and Python SDK for creating boards, frames, shapes, connectors, and collaborative visual workflows
What this skill does
# Miro API Skill
Master Miro whiteboard automation using the REST API v2 and Python SDK. This skill covers board creation, widget management, frames, shapes, connectors, templates, and real-time collaboration patterns for building automated visual workflows.
## When to Use This Skill
### USE when:
- Automating sprint retrospective board creation
- Building visual project status dashboards
- Creating automated architecture diagrams
- Setting up templated workshop boards
- Integrating Miro with CI/CD pipelines
- Automating user story mapping workflows
- Creating visual incident response boards
- Building automated onboarding boards
- Generating meeting facilitation templates
- Syncing data from external systems to Miro
### DON'T USE when:
- Simple text-based collaboration (use Slack or Teams)
- Document-focused workflows (use Notion or Confluence)
- Code-focused diagramming (use Mermaid or PlantUML)
- Real-time whiteboarding without persistence
- Personal note-taking (use Obsidian)
## Prerequisites
### Miro App Setup
```bash
# 1. Create a Miro App at https://miro.com/app/settings/user-profile/apps
# 2. Choose REST API 2.0
# 3. Configure OAuth 2.0 scopes
# Required OAuth Scopes:
# - boards:read - Read board data
# - boards:write - Create and modify boards
# - team:read - Read team information
# - identity:read - Read user identity
# - microphone:read - Read board audio (optional)
# - screen_recording - Screen recording (optional)
# App Permissions for different use cases:
# Team App: boards:read, boards:write, team:read
# User App: boards:read, boards:write, identity:read
# Admin App: All scopes + organization management
# Get Access Token via OAuth 2.0:
# 1. Redirect user to: https://miro.com/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI
# 2. Exchange code for token at: https://api.miro.com/v1/oauth/token
```
### Python Environment Setup
```bash
# Create virtual environment
python -m venv miro-env
source miro-env/bin/activate # Linux/macOS
# miro-env\Scripts\activate # Windows
# Install Miro API SDK
pip install miro-api
# Install additional dependencies
pip install python-dotenv requests httpx aiohttp
# Create requirements.txt
cat > requirements.txt << 'EOF'
miro-api>=2.0.0
python-dotenv>=1.0.0
requests>=2.31.0
httpx>=0.25.0
aiohttp>=3.9.0
Pillow>=10.0.0
EOF
# Environment variables
cat > .env << 'EOF'
MIRO_ACCESS_TOKEN=your-access-token
MIRO_CLIENT_ID=your-client-id
MIRO_CLIENT_SECRET=your-client-secret
MIRO_TEAM_ID=your-team-id
EOF
```
### API Authentication
```python
# auth.py
# ABOUTME: Miro API authentication utilities
# ABOUTME: Handles OAuth2 token management and refresh
import os
from dotenv import load_dotenv
import requests
from datetime import datetime, timedelta
load_dotenv()
class MiroAuth:
"""Miro OAuth2 authentication handler"""
BASE_URL = "https://api.miro.com"
AUTH_URL = "https://miro.com/oauth/authorize"
TOKEN_URL = "https://api.miro.com/v1/oauth/token"
def __init__(self):
self.client_id = os.environ.get("MIRO_CLIENT_ID")
self.client_secret = os.environ.get("MIRO_CLIENT_SECRET")
self.access_token = os.environ.get("MIRO_ACCESS_TOKEN")
self.refresh_token = os.environ.get("MIRO_REFRESH_TOKEN")
self.token_expires = None
def get_authorization_url(self, redirect_uri: str, state: str = None) -> str:
"""Generate OAuth2 authorization URL"""
params = {
"response_type": "code",
"client_id": self.client_id,
"redirect_uri": redirect_uri,
}
if state:
params["state"] = state
query = "&".join(f"{k}={v}" for k, v in params.items())
return f"{self.AUTH_URL}?{query}"
def exchange_code_for_token(self, code: str, redirect_uri: str) -> dict:
"""Exchange authorization code for access token"""
response = requests.post(
self.TOKEN_URL,
data={
"grant_type": "authorization_code",
"client_id": self.client_id,
"client_secret": self.client_secret,
"code": code,
"redirect_uri": redirect_uri,
},
)
response.raise_for_status()
token_data = response.json()
self.access_token = token_data["access_token"]
self.refresh_token = token_data.get("refresh_token")
self.token_expires = datetime.now() + timedelta(
seconds=token_data.get("expires_in", 3600)
)
return token_data
def refresh_access_token(self) -> dict:
"""Refresh the access token"""
response = requests.post(
self.TOKEN_URL,
data={
"grant_type": "refresh_token",
"client_id": self.client_id,
"client_secret": self.client_secret,
"refresh_token": self.refresh_token,
},
)
response.raise_for_status()
token_data = response.json()
self.access_token = token_data["access_token"]
self.refresh_token = token_data.get("refresh_token", self.refresh_token)
return token_data
def get_headers(self) -> dict:
"""Get authorization headers for API requests"""
return {
"Authorization": f"Bearer {self.access_token}",
"Content-Type": "application/json",
}
```
## Core Capabilities
### 1. Board Management
```python
# boards.py
# ABOUTME: Miro board management operations
# ABOUTME: Create, read, update, delete boards
import os
from miro_api import Miro
from dotenv import load_dotenv
load_dotenv()
# Initialize Miro client
miro = Miro(access_token=os.environ.get("MIRO_ACCESS_TOKEN"))
def create_board(name: str, description: str = "", team_id: str = None) -> dict:
"""Create a new Miro board"""
team_id = team_id or os.environ.get("MIRO_TEAM_ID")
board = miro.boards.create(
name=name,
description=description,
team_id=team_id,
policy={
"permissionsPolicy": {
"collaborationToolsStartAccess": "all_editors",
"copyAccess": "anyone",
"sharingAccess": "team_members_with_editing_rights",
},
"sharingPolicy": {
"access": "private",
"inviteToAccountAndBoardLinkAccess": "editor",
"organizationAccess": "private",
"teamAccess": "edit",
},
},
)
return {
"id": board.id,
"name": board.name,
"view_link": board.view_link,
"created_at": board.created_at,
}
def get_board(board_id: str) -> dict:
"""Get board details"""
board = miro.boards.get(board_id)
return {
"id": board.id,
"name": board.name,
"description": board.description,
"view_link": board.view_link,
"created_at": board.created_at,
"modified_at": board.modified_at,
}
def list_boards(team_id: str = None, limit: int = 50) -> list:
"""List all boards in a team"""
team_id = team_id or os.environ.get("MIRO_TEAM_ID")
boards = miro.boards.get_all(team_id=team_id, limit=limit)
return [
{
"id": board.id,
"name": board.name,
"view_link": board.view_link,
}
for board in boards
]
def update_board(board_id: str, name: str = None, description: str = None) -> dict:
"""Update board properties"""
update_data = {}
if name:
update_data["name"] = name
if description:
update_data["description"] = description
board = miro.boards.update(board_id, **update_data)
return {"id": board.id, "name": board.name, "description": board.description}
def delete_board(board_id: str) -> bool:
"""Delete a board"""
miro.boards.delete(board_id)
return True
def copy_board(board_id: str, nRelated in communication
calendly-api
IncludedCalendly scheduling automation using REST API v2 for managing event types, availability, bookings, webhooks, and scheduling workflows
slack-api
IncludedSlack bot development and workspace automation using Web API, Events API, Socket Mode, and Block Kit for building interactive messaging applications
teams-api
IncludedMicrosoft Teams automation using Graph API, Bot Framework, Adaptive Cards, and webhooks for enterprise messaging and collaboration
Customer Support Reply
IncludedCraft empathetic, effective customer support responses that solve problems
Press Release Writer
IncludedWrite professional press releases that get media attention and coverage
Internal Memo Creator
IncludedWrite clear, professional internal memos for company communication