> ## Documentation Index
> Fetch the complete documentation index at: https://docs.optexity.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Orchestration

> Coordinate multiple automations with callbacks

Orchestrate complex workflows by chaining automations using callbacks instead of polling.

## Architecture

```
Your Server                    Optexity
    │                              │
    ├──POST /inference────────────>│
    │                              ├── Execute automation
    │<─────────POST /callback──────┤
    │                              │
    └──Process result, continue────>
```

***

## Minimal Example

```python theme={null}
import asyncio
import httpx
from fastapi import FastAPI, Request
from contextlib import asynccontextmanager

callbacks: dict[str, dict] = {}
CALLBACK_TIMEOUT = 600

async def run_workflow(items: list[str]):
    async with httpx.AsyncClient() as client:
        for item in items:
            resp = await client.post(
                "https://inference.optexity.com/api/v1/inference",
                json={
                    "endpoint_name": "my-automation",
                    "input_parameters": {"email": [item]},
                    "unique_parameter_names": ["email"]
                },
            )
            task_id = resp.json()["task_id"]

            callbacks[task_id] = {"event": asyncio.Event(), "data": None}

            await asyncio.wait_for(
                callbacks[task_id]["event"].wait(),
                timeout=CALLBACK_TIMEOUT,
            )

            result = callbacks[task_id]["data"]
            print("Completed:", result)
            callbacks.pop(task_id, None)

@asynccontextmanager
async def lifespan(app: FastAPI):
    task = asyncio.create_task(run_workflow(["a@test.com", "b@test.com"]))
    yield
    task.cancel()

app = FastAPI(lifespan=lifespan)

@app.post("/receive_callback")
async def receive_callback(req: Request):
    payload = await req.json()
    task_id = payload.get("task_id")
    entry = callbacks.get(task_id)
    if entry:
        entry["data"] = payload
        entry["event"].set()
    return {"ok": True}
```

***

## Dependencies

```bash theme={null}
pip install fastapi uvicorn httpx asyncio
```

***

## Running

```bash theme={null}
uvicorn main:app --reload --port 4000
```

***

## How It Works

| Component           | Purpose                                             |
| ------------------- | --------------------------------------------------- |
| `callbacks` dict    | Stores pending tasks with asyncio Events            |
| `run_workflow`      | Starts tasks, waits for callbacks                   |
| `/receive_callback` | Receives Optexity notifications, signals completion |

### Flow

1. **Start task**: POST to Optexity inference API
2. **Register callback**: Create asyncio Event for task\_id
3. **Wait**: Event.wait() suspends until callback received
4. **Callback received**: Event.set() wakes workflow
5. **Process**: Use result, continue to next task

***

## Benefits

| Benefit    | Description                      |
| ---------- | -------------------------------- |
| No polling | Tasks complete asynchronously    |
| Efficient  | Lightweight asyncio coordination |
| Scalable   | Extend for parallel tasks        |
| Reliable   | Timeout handling included        |

<Warning>
  Your callback URL must be publicly accessible from Optexity's servers.
</Warning>
