Booking Flow (DealBookingFlow Internals)¶
The DealBookingFlow is a CrewAI event-driven flow that orchestrates the end-to-end booking process. It is defined in flows/deal_booking_flow.py and extends Flow[BookingState]. This page documents the internal mechanics of that flow --- if you are looking for a high-level overview of how campaigns move from brief to booked deal, start with the Buyer Guide Overview.
At a high level, the flow works in four phases. First, it validates the incoming campaign brief and builds an audience plan. Second, it allocates the total budget across advertising channels (branding, CTV, mobile, performance). Third, it researches inventory in parallel across all active channels, optionally negotiating pricing with the seller. Fourth, it consolidates recommendations, pauses for human approval (unless auto-approve is enabled), and executes the final bookings against the seller's OpenDirect API.
Sequence Diagram¶
sequenceDiagram
actor User as User / Campaign Manager
participant API as Buyer API
(FastAPI)
participant Flow as DealBookingFlow
(CrewAI)
participant Portfolio as Portfolio Manager
Agent
participant Channels as Channel Specialist
Agents
participant ODClient as OpenDirect
Client
participant Seller as Seller Agent
API
User->>API: POST /bookings (CampaignBrief)
API->>API: Create job (status: pending)
API-->>User: 202 {job_id, status: pending}
API->>Flow: Background task: kickoff()
Note over Flow: Step 1: Validate brief
Flow->>Flow: receive_campaign_brief()
Flow->>Flow: plan_audience()
Note over Flow: Step 2: Budget allocation
Flow->>Portfolio: allocate_budget()
Portfolio-->>Flow: Channel allocations (branding, ctv, mobile, performance)
Note over Flow: Step 3: Parallel inventory research
par Branding research
Flow->>Channels: research_branding()
Channels->>ODClient: search products, check avails
ODClient->>Seller: GET /products, POST /products/avails
Seller-->>ODClient: Product list, availability
ODClient-->>Channels: Products + pricing
Channels-->>Flow: Branding recommendations
and CTV research
Flow->>Channels: research_ctv()
Channels->>ODClient: search products, check avails
ODClient->>Seller: GET /products, POST /products/avails
Seller-->>ODClient: Product list, availability
ODClient-->>Channels: Products + pricing
Channels-->>Flow: CTV recommendations
and Performance research
Flow->>Channels: research_performance()
Channels-->>Flow: Performance recommendations
and Mobile research
Flow->>Channels: research_mobile()
Channels-->>Flow: Mobile recommendations
end
opt Negotiation (eligible tiers)
Flow->>ODClient: NegotiationClient.start_negotiation()
ODClient->>Seller: POST /proposals/{id}/counter
Seller-->>ODClient: Counter-offer / accept
ODClient-->>Flow: Negotiated pricing
end
Note over Flow: Step 4: Consolidate
Flow->>Flow: consolidate_recommendations()
Flow->>Flow: Set status: awaiting_approval
User->>API: GET /bookings/{job_id}
API-->>User: {status: awaiting_approval, recommendations: [...]}
alt auto_approve = true
Flow->>Flow: approve_all()
Flow->>Flow: _execute_bookings()
Flow->>Flow: Set status: completed
else Manual approval
User->>API: POST /bookings/{job_id}/approve
{approved_product_ids: [...]}
API->>Flow: approve_recommendations(ids)
Flow->>Flow: _execute_bookings()
Flow-->>API: {status: success, booked: N}
API-->>User: {status: success, booked: N, total_cost: X}
end
User->>API: GET /bookings/{job_id}
API-->>User: {status: completed, booked_lines: [...]}
Flow Steps¶
| Step | Method | Trigger | Description |
|---|---|---|---|
| 1 | receive_campaign_brief() |
@start() |
Validates required fields and budget |
| 2 | plan_audience() |
Listens to step 1 | Builds audience plan, estimates coverage, identifies gaps |
| 3 | allocate_budget() |
Listens to step 2 | Portfolio crew splits budget across channels |
| 4a | research_branding() |
Listens to step 3 | Branding crew searches display/video inventory |
| 4b | research_ctv() |
Listens to step 3 | CTV crew searches streaming inventory |
| 4c | research_mobile() |
Listens to step 3 | Mobile crew searches app inventory |
| 4d | research_performance() |
Listens to step 3 | Performance crew searches remarketing inventory |
| 5 | consolidate_recommendations() |
Listens to 4a-4d (OR) | Waits for all active channels, flattens recommendations |
| 6 | approve_recommendations() / approve_all() |
External call (API) | Marks recommendations as approved/rejected |
| 7 | _execute_bookings() |
Called by step 6 | Creates BookedLine entries for approved items |
Execution Status Transitions¶
stateDiagram-v2
[*] --> initialized
initialized --> brief_received: receive_campaign_brief
initialized --> validation_failed: invalid brief
brief_received --> budget_allocated: allocate_budget
budget_allocated --> researching: research_* agents
researching --> awaiting_approval: consolidate_recommendations
awaiting_approval --> executing_bookings: approve
executing_bookings --> completed: bookings done
budget_allocated --> failed: error
researching --> failed: error
executing_bookings --> failed: error
These states are tracked in BookingState.execution_status using the ExecutionStatus enum.
Negotiation Between Research and Booking
For Agency and Advertiser tier buyers, a negotiation phase can occur between the research and booking steps. The NegotiationClient handles multi-turn price negotiation with the seller agent before orders are placed. See the Negotiation Guide for details on configuring negotiation strategies.