Async Python talks to Trends API with httpx. The URL and JSON shape are the same as sync: POST https://api.trendsapi.ai/api, Bearer key, mode plus source. The envelope still has a string body. That string must be parsed a second time. Docs: the API reference. Caps: pricing. YouTube as a labeled source: the YouTube guide.

await client.post

pip install httpx
import json
import os
import httpx

async def series(keyword: str) -> dict:
    timeout = httpx.Timeout(10.0, read=60.0)
    async with httpx.AsyncClient(timeout=timeout) as client:
        resp = await client.post(
            "https://api.trendsapi.ai/api",
            headers={
                "Authorization": f"Bearer {os.environ['TRENDSAPI_API_KEY']}",
                "Content-Type": "application/json",
            },
            json={
                "mode": "get_time_series",
                "source": "youtube",
                "keyword": keyword,
            },
        )
        resp.raise_for_status()
        outer = resp.json()
        return json.loads(outer["body"])

youtube plus a title is a labeled sample, not a live pull in this file. get_time_series takes exactly one source.

httpx.Timeout and limits

Timeout(10.0, read=60.0) splits connect from read. A default of none will hang a worker. limits=httpx.Limits(max_keepalive_connections=5) keeps a pool from growing without a bound.

Cancel a hung get_time_series

asyncio.wait_for(series("air fryer recipes"), timeout=70) raises TimeoutError if both the client timeout and the shield fail. Do not retry that error as if it were empty data. Log the keyword and move on.

Async generator over sources

get_growth can take a comma-separated source list. That is one POST. Spawning one task per source is the other shape and needs a semaphore. Prefer the comma list when the question is point-to-point growth on several platforms. Prefer one get_time_series per source when the next step is a chart. The product MCP server at https://api.trendsapi.ai/mcp is another async consumer of the same modes.