# How to Implement Callback Functions for Processing Command Output in OpenBB

> Learn to implement callback functions for processing command output in OpenBB. Define async callbacks and pass them to amake_request for efficient model building.

- Repository: [OpenBB/OpenBB](https://github.com/OpenBB-finance/OpenBB)
- Tags: how-to-guide
- Published: 2026-03-06

---

**To process command output in OpenBB, define an async callback function that receives the raw `aiohttp` response object and pass it to the `amake_request` helper when building provider models.**

The OpenBB Platform uses an **asynchronous request architecture** that separates data fetching from data transformation. By implementing **callback functions for processing command output in OpenBB**, you can intercept raw HTTP responses, apply custom parsing logic, and return structured data that integrates seamlessly with the CLI's display and registry systems.

## Understanding the Callback Architecture in OpenBB

OpenBB processes data-fetching commands through the `amake_request` helper located in [`openbb_core/provider/utils/helpers.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/openbb_core/provider/utils/helpers.py). This utility accepts a `response_callback` parameter—an async function that transforms the raw response into the shape expected by the command's Pydantic model.

### The Async Request Helper (`amake_request`)

The `amake_request` function serves as the bridge between HTTP transport and data processing. When a command executes, the helper opens an `aiohttp` session, fetches the response, then awaits your callback with the signature `async def callback(response: ClientResponse, extra: any)`. Because the callback runs inside the request coroutine, you can perform additional async I/O such as secondary API calls or file extraction without blocking the CLI.

### Where Callbacks Live in the Codebase

Provider-specific callbacks are typically organized in utility modules:

- **[`openbb_platform/providers/tradingeconomics/openbb_tradingeconomics/utils/helpers.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/openbb_platform/providers/tradingeconomics/openbb_tradingeconomics/utils/helpers.py)** – Generic HTTP response handling for JSON, CSV, and ZIP formats
- **[`openbb_platform/providers/sec/openbb_sec/utils/helpers.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/openbb_platform/providers/sec/openbb_sec/utils/helpers.py)** – SEC-specific response handling for filings and compressed archives  
- **[`openbb_platform/providers/intrinio/openbb_intrinio/utils/helpers.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/openbb_platform/providers/intrinio/openbb_intrinio/utils/helpers.py)** – Pagination-aware async JSON processing

The CLI controllers in [`cli/openbb_cli/controllers/base_controller.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/cli/openbb_cli/controllers/base_controller.py) and [`cli/openbb_cli/controllers/base_platform_controller.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/cli/openbb_cli/controllers/base_platform_controller.py) handle the `--register_obbject` flag, which determines whether processed output gets stored in the OBBject registry.

## Implementing a Custom Callback Function

To implement **callback functions for processing command output in OpenBB**, create an async function that accepts the `ClientResponse` object and returns a Python object (dict, list, or DataFrame).

### Simple CSV Parsing Callback

For providers returning CSV data, implement a callback that streams and parses the text:

```python

# File: openbb_platform/providers/example/utils/helpers.py

import csv
from io import StringIO
from aiohttp import ClientResponse
from typing import List, Dict

async def csv_callback(response: ClientResponse, _: any) -> List[Dict]:
    """Read a CSV response and return a list of dictionaries."""
    text = await response.text()
    reader = csv.DictReader(StringIO(text))
    return [row for row in reader]

```

Use this callback when constructing your provider model:

```python

# File: openbb_platform/providers/example/models/my_data.py

from ...utils.helpers import csv_callback
from openbb_core.provider.utils.helpers import amake_request

async def fetch_data(symbol: str):
    url = f"https://example.com/data/{symbol}.csv"
    raw = await amake_request(url, response_callback=csv_callback)
    return raw

```

### Enriched Data Callback with OBBject Registration

To add metadata before the CLI registers the result, create an enrichment callback:

```python

# File: cli/openbb_cli/controllers/custom_controller.py

from datetime import datetime
from aiohttp import ClientResponse

async def enrich_callback(response: ClientResponse, _: any):
    """Add timestamp and source metadata to the response."""
    data = await response.json()
    data["fetched_at"] = datetime.utcnow().isoformat()
    data["source"] = "custom_api"
    return data

```

When users pass the `--register_obbject` flag, `BasePlatformController` (lines 165-168) automatically stores the enriched object in the session registry using the logic defined in [`base_controller.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/base_controller.py) (lines 734-735).

### Handling Paginated Responses

For APIs with pagination, implement recursive callbacks that follow `next_page` URLs:

```python

# File: openbb_platform/providers/intrinio/openbb_intrinio/utils/helpers.py

from aiohttp import ClientResponse
from typing import List, Dict

async def pagination_callback(response: ClientResponse, _: any) -> List[Dict]:
    """Concatenate paginated Intrinio responses into a single list."""
    data = await response.json()
    results = data.get("data", [])
    
    while data.get("next_page"):
        next_url = data["next_page"]
        # Fetch next page using the same callback pattern

        next_data = await amake_request(next_url, response_callback=pagination_callback)
        results.extend(next_data.get("data", []))
        data = next_data
    
    return results

```

## Integrating Callbacks into Provider Models

The command flow follows a strict injection pattern:

1. **User executes CLI command** (e.g., `openbb stocks.load AAPL`)
2. **Controller parses arguments** via `BaseController.parse_known_args_and_warn`
3. **Provider model builds URL** and calls `amake_request(url, response_callback=my_callback)`
4. **Callback transforms raw response** into the expected data structure
5. **Model validates data** through Pydantic and returns to CLI

You do not need to modify command-level logic—the callback is injected at the request construction point in the provider model file (e.g., [`openbb_platform/providers/sec/openbb_sec/models/sec_filing.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/openbb_platform/providers/sec/openbb_sec/models/sec_filing.py)).

## Registering Processed Output with the OBBject Registry

OpenBB's CLI maintains an **OBBject registry** for persisting command results across the session. To enable this for your custom callback:

1. Ensure your callback returns a serializable object (dict, list, or Pydantic model)
2. Users must append `--register_obbject` when running the command
3. `BasePlatformController` detects the flag and stores the result via `session.obbject_registry.add()`

Access registered objects later using the `results` command with the appropriate key.

## Summary

- **Define async callbacks** with the signature `async def callback(response: ClientResponse, extra: any)` to intercept HTTP responses before they reach the CLI.
- **Pass callbacks to `amake_request`** in your provider model to transform raw data into structured formats without modifying core CLI code.
- **Leverage existing infrastructure** by using the `--register_obbject` flag (handled in [`base_controller.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/base_controller.py) and [`base_platform_controller.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/base_platform_controller.py)) to persist processed output in the OBBject registry.
- **Handle complex scenarios** like pagination or file extraction within the callback since it executes inside the async request coroutine.

## Frequently Asked Questions

### What is the exact function signature for an OpenBB response callback?

An OpenBB response callback must be an async function accepting two parameters: `response` (an `aiohttp.ClientResponse` object) and `extra` (typically `None` or a session context). The function should return a Python object such as a dictionary, list, or Pydantic model. This signature is required by the `amake_request` helper in [`openbb_core/provider/utils/helpers.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/openbb_core/provider/utils/helpers.py).

### Where should I place custom callback functions in the OpenBB codebase?

Place custom callbacks in the [`utils/helpers.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/utils/helpers.py) file within your specific provider directory (e.g., [`openbb_platform/providers/your_provider/openbb_your_provider/utils/helpers.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/openbb_platform/providers/your_provider/openbb_your_provider/utils/helpers.py)). For CLI-specific post-processing, you can define callbacks directly in the controller file at [`cli/openbb_cli/controllers/custom_controller.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/cli/openbb_cli/controllers/custom_controller.py) or import them from utility modules.

### How does the `--register_obbject` flag interact with my callback output?

When users include `--register_obbject` in their command, `BaseController` parses the flag (as implemented in [`cli/openbb_cli/controllers/base_controller.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/cli/openbb_cli/controllers/base_controller.py) lines 734-735) and `BasePlatformController` stores the returned object in the session registry (lines 165-168 in [`base_platform_controller.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/base_platform_controller.py)). Your callback must return a serializable object for successful registration.

### Can I perform additional async operations inside a callback?

Yes. Because `amake_request` awaits your callback within the active `aiohttp` session, you can safely perform additional async I/O operations such as secondary API calls, database queries, or file system operations. This is particularly useful for pagination patterns like those implemented in the Intrinio provider.