Miro REST API Integration and Board Automation with Python

Application Configuration

Navigate to the Miro dashboard, access your profile settings, and select "Your apps" to initialize a new application. If you are not currently assigned to a workspace, the system will prompt you to create one, typically defaulting to a development team. Define the application name during setup. The "Expire user authorization token" setting provides an extra layer of security by allowing you to invalidate previously issued tokens. The "App Publication Status" controls whether your integration is available to external users; keeping it unpublished is suitable for private tools. Under "Permissions", enable the necessary OAuth scopes such as boards:read and boards:write, then install the app to generate your access token.

Web SDK vs REST API

Feature / RequirementMiro Web SDKMiro REST APIs
Real-time user interaction via UI extension points (e.g., custom form panels)SupportedNot Supported
Access board itemsSupportedSupported
Access team-level dataSupportedSupported
Access organization-level dataSupportedSupported
Third-party integration originLaunched from MiroLaunched from external service
Board state requirementMust be open/onlineCan be offline
Backend hostingOptionalRequired
Programming languageTypeScript / JavaScriptAny

API Interaction with Python

Prerequisites

Utilize the requests library for HTTP interactions.

import requests

ACCESS_TOKEN = "YOUR_ACCESS_TOKEN"
api_client = requests.Session()
base_headers = {
    "Authorization": f"Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/"
}

Connection Management

Leaving HTTP connections open after API calls exhausts system resources, often triggering ConnectionError or Max retries exceeded exceptions. Always use context managers to ensure connections are properly terminated.

with api_client.get(url, headers=base_headers) as resp:
    resp.raise_for_status()
    data = resp.()

Board Initialization

Method 1: Extract the board identifier directly from the URL of a manually created board: https://miro.com/app/board/{board_identifier}/

Method 2: Programmatically generate a new board.

boards_endpoint = "https://api.miro.com/v2/boards"
with api_client.post(boards_endpoint, headers=base_headers) as resp:
    resp.raise_for_status()
    board_identifier = resp.()["id"]

App Cards vs Standard Cards

App Cards integrate external third-party data, acting as preview widgets with custom fields and status indicators. Standard Cards are native widgets used to display basic task information like titles and descriptions.

Creating an App Card

app_card_url = f"https://api.miro.com/v2/boards/{board_identifier}/app_cards"
app_card_payload = {
    "data": {
        "fields": [
            {
                "fillColor": "#ff5733",
                "iconShape": "round",
                "textColor": "#ffffff",
                "iconUrl": "https://cdn.example.com/icon.png",
                "tooltip": "Task priority level",
                "value": "Priority: High"
            }
        ],
        "description": "External synchronization record",
        "title": "Synced Task Item",
        "status": "connected"
    },
    "style": {"fillColor": "#f5f5f5"},
    "position": {"x": 500, "y": 500},
    "geometry": {"height": 100, "width": 300}
}

with api_client.post(app_card_url, =app_card_payload, headers=base_headers) as resp:
    resp.raise_for_status()
    print(resp.())

Creating a Standard Card

std_card_url = f"https://api.miro.com/v2/boards/{board_identifier}/cards"
std_card_payload = {
    "data": {
        "assigneeId": "MEMBER_ID",
        "description": "Scheduled maintenance window",
        "dueDate": "2024-11-01T10:00:00.000Z",
        "title": "Server Maintenance"
    },
    "style": {"cardTheme": "#2d9bf0"},
    "position": {"x": 800, "y": 800},
    "geometry": {"height": 80, "width": 350}
}

with api_client.post(std_card_url, =std_card_payload, headers=base_headers) as resp:
    resp.raise_for_status()
    print(resp.())

Establishing Connectors

connector_url = f"https://api.miro.com/v2/boards/{board_identifier}/connectors"
connector_payload = {
    "startItem": {"id": origin_item_id},
    "endItem": {"id": destination_item_id},
    "captions": [{"content": "Depends on"}]
}

with api_client.post(connector_url, =connector_payload, headers=base_headers) as resp:
    resp.raise_for_status()
    print(resp.())

Retrieving Item Data

Fetch all items on a board:

items_url = f"https://api.miro.com/v2/boards/{board_identifier}/items"
with api_client.get(items_url, headers=base_headers) as resp:
    resp.raise_for_status()
    all_items = resp.().get("data", [])

Fetch a specific card by its identifier:

specific_item_url = f"https://api.miro.com/v2/boards/{board_identifier}/cards/{target_item_id}"
with api_client.get(specific_item_url, headers=base_headers) as resp:
    resp.raise_for_status()
    item_data = resp.()

Modifying Card Attributes

update_url = f"https://api.miro.com/v2/boards/{board_identifier}/cards/{target_card_id}"
update_payload = {"data": {"title": "Updated Task Title"}}

with api_client.patch(update_url, =update_payload, headers=base_headers) as resp:
    if resp.status_code == 200:
        print("Update successful")

Removing Items

delete_url = f"https://api.miro.com/v2/boards/{board_identifier}/items/{target_item_id}"
with api_client.delete(delete_url, headers=base_headers) as resp:
    if resp.status_code == 204:
        print("Deletion successful")

Tags: Miro REST API python Web SDK Integration

Posted on Sat, 26 Sep 2026 16:45:45 +0000 by rostislav