Skip to main content

Overview

The async API pattern is ideal when you want to submit multiple long-running tasks and check their status later. Instead of waiting for each run to complete, you submit all requests and get back run IDs that you can poll for completion.

How It Works

  1. Submit requests to /v1/automation/run-async, which returns corresponding run_ids, which you will need if you want to check the status of a particular run.
  2. Check individual runs with GET /v1/runs/:id to check status
  3. Or fetch all runs with GET /v1/runs to monitor batch progress

Basic Example

Submit multiple mino runs and poll for completion:
import asyncio
import aiohttp

async def submit_mino_run(session, url, goal):
    """Submit a mino run and return the run_id"""
    async with session.post(
        "https://mino.ai/v1/automation/run-async",
        headers={
            "X-API-Key": "YOUR_API_KEY",
            "Content-Type": "application/json",
        },
        json={
            "url": url,
            "goal": goal,
        },
    ) as response:
        result = await response.json()
        return result["run_id"]

async def get_run_status(session, run_id):
    """Get the status of a specific run"""
    async with session.get(
        f"https://mino.ai/v1/runs/{run_id}",
        headers={
            "X-API-Key": "YOUR_API_KEY",
        },
    ) as response:
        return await response.json()

async def wait_for_completion(session, run_id, poll_interval=2):
    """Poll a run until it completes"""
    while True:
        run = await get_run_status(session, run_id)
        status = run.get("status")

        if status in ["COMPLETED", "FAILED", "CANCELLED"]:
            return run

        await asyncio.sleep(poll_interval)

async def main():
    # Define your batch of tasks
    tasks_to_run = [
        {
            "url": "https://scrapeme.live/shop/",
            "goal": "Extract all available products on page two with their name, price, and review rating (if available)"
        },
        {
            "url": "https://books.toscrape.com/",
            "goal": "Extract all available books on page two with their title, price, and review rating (if available)"
        },
    ]

    async with aiohttp.ClientSession() as session:
        # Step 1: Submit all mino runs and collect run_ids
        print("Submitting mino runs...")
        submit_tasks = [
            submit_mino_run(session, task["url"], task["goal"])
            for task in tasks_to_run
        ]
        run_ids = await asyncio.gather(*submit_tasks)
        print(f"Submitted {len(run_ids)} runs: {run_ids}")

        # Step 2: Wait for all runs to complete
        print("Waiting for completion...")
        completion_tasks = [
            wait_for_completion(session, run_id)
            for run_id in run_ids
        ]
        results = await asyncio.gather(*completion_tasks)

        # Step 3: Process results
        for i, run in enumerate(results):
            print(f"Run {i + 1} ({run['run_id']}):")
            print(f"  Status: {run['status']}")
            if run['status'] == 'COMPLETED':
                print(f"  Result: {run.get('result')}")

# Run the async main function
asyncio.run(main())

Fire and Forget Pattern

Submit tasks without waiting for completion:
async def main():
    tasks_to_run = [
        {"url": "https://example.com/page1", "goal": "Extract product info"},
        {"url": "https://example.com/page2", "goal": "Extract product info"},
        {"url": "https://example.com/page3", "goal": "Extract product info"},
    ]

    async with aiohttp.ClientSession() as session:
        # Submit all tasks
        submit_tasks = [
            submit_mino_run(session, task["url"], task["goal"])
            for task in tasks_to_run
        ]
        run_ids = await asyncio.gather(*submit_tasks)

        print(f"Submitted {len(run_ids)} runs")
        print(f"Run IDs: {run_ids}")
        print("Check status later using GET /v1/runs/:id")

asyncio.run(main())

When to Use Async vs Sync

Use CaseAPI PatternWhy
Quick tasks (<30s)Sync /runSimpler code, immediate results
Long-running tasksAsync /run-asyncDon’t block, check later
Large batchesAsync /run-asyncSubmit all at once, monitor progress
Fire and forgetAsync /run-asyncNo need to wait
Real-time feedbackSSE /run-sseStream progress events

Best Practices

Polling Interval

  • Short tasks (under 1 min): Poll every 2-3 seconds
  • Medium tasks (1-5 min): Poll every 5-10 seconds
  • Long tasks (over 5 min): Poll every 30-60 seconds

Error Handling

Always check run status and handle failures:
Python
async def process_completed_run(run):
    if run["status"] == "COMPLETED":
        return run.get("result")
    elif run["status"] == "FAILED":
        error = run.get("error", {}).get("message", "Unknown error")
        print(f"Run {run['run_id']} failed: {error}")
        return None
    elif run["status"] == "CANCELLED":
        print(f"Run {run['run_id']} was cancelled")
        return None

API Reference