Bookings API¶
A booking is the buyer agent's end-to-end process of turning a campaign brief into confirmed advertising deals. You submit a brief describing your campaign objectives, budget, audience, and timeline; the buyer agent allocates budget across channels, researches inventory from connected sellers, optionally negotiates pricing, and presents recommendations for your approval. Once approved, the agent books confirmed line items via the seller's OpenDirect API. Use these endpoints to start a booking, poll its progress, and approve or reject the resulting recommendations.
The bookings endpoints manage the full campaign booking lifecycle --- from brief submission through approval to deal execution.
Status Lifecycle¶
| Status | Meaning |
|---|---|
pending |
Job created, background flow starting |
running |
Budget allocation, inventory research, and negotiation (if eligible) in progress |
awaiting_approval |
Recommendations ready for human review |
completed |
Deals booked (or no recommendations approved) |
failed |
An error occurred during the flow |
Negotiation During the Running Phase
During the running phase, the buyer agent may negotiate pricing with the seller for eligible buyer tiers (Agency and Advertiser). The kpis.target_cpm field in the campaign brief can drive negotiation behavior by setting the buyer's target price. See the Negotiation Guide for details.
POST /bookings¶
Start a new booking workflow. The flow runs in the background; poll GET /bookings/{job_id} for progress.
Request Body --- BookingRequest¶
| Field | Type | Required | Description |
|---|---|---|---|
brief |
CampaignBrief |
yes | Campaign details (see below) |
auto_approve |
bool |
no | Automatically approve all recommendations. Default: false |
CampaignBrief¶
| Field | Type | Required | Description |
|---|---|---|---|
name |
string (1-100 chars) |
yes | Campaign name |
objectives |
list[string] (min 1) |
yes | Campaign objectives (e.g. brand_awareness, reach, conversions) |
budget |
float (> 0) |
yes | Total campaign budget |
start_date |
string (YYYY-MM-DD) |
yes | Campaign start date |
end_date |
string (YYYY-MM-DD) |
yes | Campaign end date |
target_audience |
object |
yes | Audience targeting specification |
kpis |
object |
no | Key performance indicators |
channels |
list[string] |
no | Preferred channels (e.g. branding, ctv, mobile_app, performance) |
Response --- BookingResponse¶
| Field | Type | Description |
|---|---|---|
job_id |
string |
Unique job identifier (UUID) |
status |
string |
Initial status: pending |
message |
string |
Human-readable next-step message |
Example¶
curl -X POST http://localhost:8001/bookings \
-H "Content-Type: application/json" \
-d '{
"brief": {
"name": "Q3 Awareness Push",
"objectives": ["brand_awareness"],
"budget": 25000,
"start_date": "2026-07-01",
"end_date": "2026-09-30",
"target_audience": {
"demographics": {"age": "18-34"},
"interests": ["gaming", "technology"]
},
"kpis": {"target_cpm": 10}
},
"auto_approve": false
}'
GET /bookings/{job_id}¶
Retrieve the current status of a booking workflow.
Response --- BookingStatus¶
| Field | Type | Description |
|---|---|---|
job_id |
string |
Job identifier |
status |
string |
Current status (see lifecycle above) |
progress |
float |
Progress from 0.0 to 1.0 |
budget_allocations |
object \| null |
Channel budget splits |
recommendations |
list[object] \| null |
Product recommendations pending approval |
booked_lines |
list[object] \| null |
Confirmed booked line items |
errors |
list[string] \| null |
Error messages, if any |
created_at |
string |
ISO 8601 creation timestamp |
updated_at |
string |
ISO 8601 last-update timestamp |
Example¶
POST /bookings/{job_id}/approve¶
Approve specific product recommendations for booking. Only valid when the job status is awaiting_approval.
Request Body --- ApprovalRequest¶
| Field | Type | Required | Description |
|---|---|---|---|
approved_product_ids |
list[string] |
yes | Product IDs to approve |
Response¶
| Field | Type | Description |
|---|---|---|
status |
string |
success or failed |
approved_count |
int |
Number of products approved |
booked |
int |
Number of line items booked |
total_cost |
float |
Total cost of booked items |
Example¶
curl -X POST http://localhost:8001/bookings/a1b2c3d4-.../approve \
-H "Content-Type: application/json" \
-d '{"approved_product_ids": ["prod_001", "prod_003"]}'
POST /bookings/{job_id}/approve-all¶
Approve all pending recommendations for booking. Only valid when the job status is awaiting_approval.
Response¶
| Field | Type | Description |
|---|---|---|
status |
string |
success or failed |
booked |
int |
Number of line items booked |
total_impressions |
int |
Total impressions across booked lines |
total_cost |
float |
Total cost of booked items |
Example¶
GET /bookings¶
List all booking jobs, optionally filtered by status.
Query Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
status |
string |
(none) | Filter by status (e.g. awaiting_approval, completed) |
limit |
int |
20 | Maximum number of results |
Response¶
| Field | Type | Description |
|---|---|---|
jobs |
list[object] |
Job summaries (job_id, status, campaign_name, budget, created_at) |
total |
int |
Total number of matching jobs |
Example¶
Error Handling¶
All booking endpoints return structured error responses with an HTTP status code and a JSON body containing error and detail fields.
Error Codes¶
| Endpoint | HTTP Status | error |
When |
|---|---|---|---|
POST /bookings |
400 |
invalid_brief |
Required brief fields missing or invalid (e.g., budget <= 0, empty objectives, end_date before start_date) |
POST /bookings |
422 |
validation_error |
Brief payload fails Pydantic schema validation |
GET /bookings/{job_id} |
404 |
not_found |
No booking job exists with the given ID |
POST /bookings/{job_id}/approve |
404 |
not_found |
No booking job exists with the given ID |
POST /bookings/{job_id}/approve |
409 |
invalid_status |
Job is not in awaiting_approval status |
POST /bookings/{job_id}/approve |
400 |
invalid_products |
None of the submitted product IDs match pending recommendations |
POST /bookings/{job_id}/approve-all |
404 |
not_found |
No booking job exists with the given ID |
POST /bookings/{job_id}/approve-all |
409 |
invalid_status |
Job is not in awaiting_approval status |
GET /bookings |
422 |
validation_error |
Invalid query parameter value (e.g., non-integer limit) |
| any | 500 |
internal_error |
Unexpected server error during booking flow execution |
Booking Flow Failures¶
When the background booking flow fails (seller unreachable, budget allocation error, etc.), the job transitions to failed status rather than returning an HTTP error. Poll GET /bookings/{job_id} and check the errors array: