Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: BillboardBug Public Business API
description: 'The BillboardBug Public API lets you manage your deals, posts, and storefronts programmatically. You can also use the API to generate AI images — useful for creating deal artwork without a design tool. ## Getting Started
1. **Create an account** at https://app.billboardbug.com if you don''t have one already. 2. Log in and navigate to **Settings → API Keys** to generate a key. 3. Pass the key in the `X-Api-Key` header on every request. All content created or modified through the API is associated with the account that owns the key. If that account is suspended the key will be rejected. ## Creating a Deal
**Step 0 — (Optional) Generate an image with AI**
Use the image generation endpoint to create deal artwork from a text prompt — no design tool needed. Grok is recommended for its flexible aspect ratio support. ```
POST /ai/image
X-Api-Key:
X-Version: 1
Content-Type: application/json
```
```json
{
"prompt": "A bright summer sale banner for a clothing store, bold colors",
"aiProvider": 5,
"width": 640,
"height": 373
}
```
The response contains a `base64Data` field (`data:image/jpeg;base64,...`) which you can convert
to a file and upload in Step 1. See **POST /ai/image** for provider options and resolution details. **Step 1 — Upload an image or video**
Upload an image (recommended 640 × 373 px JPEG) using category `billboard-image`, or a video (640 × 373 px) using category `billboard-video`. Save the `id` from the response and pass it as `imageId` or `videoId` in the deal request. ```
POST /blobs?category=billboard-image
X-Api-Key:
X-Version: 3
Content-Type: multipart/form-data
file=
```
Response:
```json
{ "id": "abc123.jpg" }
```
**Step 2 — Create the deal**
Pass the blob `id` as `imageId`. Hours use `HH:MM` (24-hour). Omit `altitudeMeters` for a standard pole mount. ```
POST /business/quick-create-deal
X-Api-Key:
X-Version: 1
Content-Type: application/json
```
```json
{
"title": "Summer Sale",
"description": "20% off this weekend.",
"imageId": "abc123.jpg",
"name": "My Store",
"locationDescription": "123 Main St, Springfield, IL",
"locationLat": 39.7817,
"locationLng": -89.6501,
"mondayEnabled": true, "monday24Hours": false,
"mondayOpen": "09:00", "mondayClose": "17:00",
"tuesdayEnabled": true, "tuesday24Hours": false,
"tuesdayOpen": "09:00", "tuesdayClose": "17:00",
"wednesdayEnabled": true, "wednesday24Hours": false,
"wednesdayOpen": "09:00", "wednesdayClose": "17:00",
"thursdayEnabled": true, "thursday24Hours": false,
"thursdayOpen": "09:00", "thursdayClose": "17:00",
"fridayEnabled": true, "friday24Hours": false,
"fridayOpen": "09:00", "fridayClose": "17:00",
"saturdayEnabled": true, "saturday24Hours": false,
"saturdayOpen": "09:00", "saturdayClose": "17:00",
"sundayEnabled": true, "sunday24Hours": false,
"sundayOpen": "09:00", "sundayClose": "17:00",
"isEnabled": true
}
```
The response contains `storefrontId` and `billboardId` — save these to update the deal later. **Featured deals (optional)**
Setting `isFeatured: true` on a deal promotes it and incurs a daily cost. The per-day rate is returned by
`GET /global-config/all` as `billboardDayAdCost`, which is the dollar amount × 100 with no cents
(e.g. `500` = $5.00/day). Discount options are available for purchase under Business → Discounts. Your account must have a billing method on file to set a deal as featured. **Step 3 — Update the deal**
Use the same body shape as create. ```
PUT /business/quick-update-deal/{storefrontId}/{billboardId}
X-Api-Key:
X-Version: 1
Content-Type: application/json
```
## Creating a Post
Posts are standalone pieces of content (text, image, or video) attached to your account. To comment on an existing post supply `parentPostId`. **Step 1 — (Optional) Upload an image or video**
Upload an image (recommended width: 640 px, height varies) using category `post-image`, or a video using category `post-video`. Save the `id` and pass it as `imageId` or `videoId` in the post request.'
version: 1.0.0
security:
- ApiKey: []
tags:
- name: Business
paths:
/business/storefront-categories:
get:
tags:
- Business
summary: List all storefront categories
description: 'Returns the full list of categories available for use when creating or updating a deal.
Pass the category `id` as the `categoryId` field in create/update deal requests.'
responses:
'200':
description: Array of categories.
content:
text/plain:
schema:
type: array
items:
$ref: '#/components/schemas/StorefrontCategoryResponse'
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/StorefrontCategoryResponse'
text/json:
schema:
type: array
items:
$ref: '#/components/schemas/StorefrontCategoryResponse'
operationId: getBusinessStorefrontCategories
x-operation-id-source: derived
/business/quick-create-deal:
post:
tags:
- Business
summary: Create a new deal
description: 'Creates a storefront (business location) and a billboard (the deal/ad) in a single request.
The returned `storefrontId` and `billboardId` can be used to update the deal later.
To attach an image or video, first upload it via `POST /blobs` with category `billboard-image`
or `billboard-video`, then pass the returned `id` as `imageId` or `videoId` here.
**`altitudeMeters`** — offset from the user''s ground level. Omit (or pass `null`) to place the billboard
on a standard pole. When specified, the billboard floats that many meters above the ground at the given location.'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/QuickUpdateDealRequest'
text/json:
schema:
$ref: '#/components/schemas/QuickUpdateDealRequest'
application/*+json:
schema:
$ref: '#/components/schemas/QuickUpdateDealRequest'
responses:
'200':
description: The created deal.
content:
text/plain:
schema:
$ref: '#/components/schemas/DealResponseDetails'
application/json:
schema:
$ref: '#/components/schemas/DealResponseDetails'
text/json:
schema:
$ref: '#/components/schemas/DealResponseDetails'
'400':
description: Validation error.
operationId: postBusinessQuickCreateDeal
x-operation-id-source: derived
/business/quick-get-deals:
get:
tags:
- Business
summary: List your deals
description: Returns a paginated list of all deals belonging to the authenticated account.
parameters:
- name: limit
in: query
description: Max results to return (1–100, default 25).
style: form
schema:
type: integer
format: int32
default: 25
- name: offset
in: query
description: Number of results to skip for pagination (default 0).
style: form
schema:
type: integer
format: int32
default: 0
responses:
'200':
description: Array of deals.
content:
text/plain:
schema:
type: array
items:
$ref: '#/components/schemas/DealResponse'
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/DealResponse'
text/json:
schema:
type: array
items:
$ref: '#/components/schemas/DealResponse'
operationId: getBusinessQuickGetDeals
x-operation-id-source: derived
/business/quick-update-deal/{storefrontId}/{billboardId}:
put:
tags:
- Business
summary: Update an existing deal
description: 'Updates the storefront and billboard identified by the given IDs. Both IDs are returned
when a deal is created via `POST /business/quick-create-deal` or listed via `GET /business/quick-get-deals`.
To update the image or video, upload a new file via `POST /blobs` first and pass the
new blob `id` as `imageId` or `videoId`.'
parameters:
- name: storefrontId
in: path
description: The storefront ID of the deal to update.
required: true
style: simple
schema:
type: string
format: uuid
- name: billboardId
in: path
description: The billboard ID of the deal to update.
required: true
style: simple
schema:
type: string
format: uuid
requestBody:
description: The updated deal fields.
content:
application/json:
schema:
$ref: '#/components/schemas/QuickUpdateDealRequest'
text/json:
schema:
$ref: '#/components/schemas/QuickUpdateDealRequest'
application/*+json:
schema:
$ref: '#/components/schemas/QuickUpdateDealRequest'
responses:
'200':
description: The updated deal.
content:
text/plain:
schema:
$ref: '#/components/schemas/DealResponseDetails'
application/json:
schema:
$ref: '#/components/schemas/DealResponseDetails'
text/json:
schema:
$ref: '#/components/schemas/DealResponseDetails'
'400':
description: Validation error.
operationId: putBusinessQuickUpdateDealByStorefrontIdByBillboardId
x-operation-id-source: derived
/business/deals/search:
get:
tags:
- Business
summary: Search deals
description: 'Returns deals matching the given search term. Requires authentication.
The `search` parameter must be at least 3 characters.
**Example request:**
```
GET /business/deals/search?search=pizza&limit=10&offset=0
```
**Example response:**
```json
[
{
"accountId": "a1b2c3d4-0000-0000-0000-000000000000",
"billboardId": "a1b2c3d4-0000-0000-0000-000000000001",
"storefrontId": "a1b2c3d4-0000-0000-0000-000000000002",
"title": "50% off all pizzas tonight",
"description": "Dine-in only. Valid until 10pm.",
"created": "2024-01-01T00:00:00Z",
"updated": "2024-01-02T00:00:00Z",
"configureStart": false,
"start": null,
"configureEnd": false,
"end": null,
"storefrontName": "Mario''s Pizza",
"locationDescription": "123 Main St, Springfield",
"locationLat": 37.7749,
"locationLng": -122.4194,
"altitudeMeters": null,
"categoryId": "a1b2c3d4-0000-0000-0000-000000000003",
"isFavorited": false,
"isReported": false,
"storefrontImageId": "img_abc123",
"billboardImageId": "img_def456",
"billboardVideoId": null,
"isEnabled": true,
"isFeatured": true,
"unfeatureAt": null,
"publicApi": true
}
]
```'
parameters:
- name: limit
in: query
description: Max results to return (1–100, default 25).
style: form
schema:
type: integer
format: int32
- name: offset
in: query
description: Number of results to skip for pagination (default 0).
style: form
schema:
type: integer
format: int32
- name: search
in: query
description: Search term (minimum 3 characters).
style: form
schema:
type: string
responses:
'200':
description: Array of matching deals.
content:
text/plain:
schema:
type: array
items:
$ref: '#/components/schemas/DealResponse'
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/DealResponse'
text/json:
schema:
type: array
items:
$ref: '#/components/schemas/DealResponse'
'400':
description: Search term must be at least 3 characters.
operationId: getBusinessDealsSearch
x-operation-id-source: derived
/business/deal/{storefrontId}/{billboardId}:
get:
tags:
- Business
summary: Get deal details
description: 'Returns full details for a single deal by storefront and billboard ID. Does not require authentication.
**Example request:**
```
GET /business/deal/a1b2c3d4-0000-0000-0000-000000000002/a1b2c3d4-0000-0000-0000-000000000001?isFromAd=false
```
**Example response:**
```json
{
"accountId": "a1b2c3d4-0000-0000-0000-000000000000",
"billboardId": "a1b2c3d4-0000-0000-0000-000000000001",
"storefrontId": "a1b2c3d4-0000-0000-0000-000000000002",
"title": "50% off all pizzas tonight",
"description": "Dine-in only. Valid until 10pm.",
"created": "2024-01-01T00:00:00Z",
"updated": "2024-01-02T00:00:00Z",
"configureStart": false,
"start": null,
"configureEnd": false,
"end": null,
"storefrontName": "Mario''s Pizza",
"locationDescription": "123 Main St, Springfield",
"locationLat": 37.7749,
"locationLng": -122.4194,
"altitudeMeters": null,
"categoryId": "a1b2c3d4-0000-0000-0000-000000000003",
"isFavorited": false,
"isReported": false,
"storefrontImageId": "img_abc123",
"billboardImageId": "img_def456",
"billboardVideoId": null,
"isEnabled": true,
"isFeatured": false,
"unfeatureAt": null,
"publicApi": true,
"mondayEnabled": true,
"monday24Hours": false,
"mondayOpen": "09:00",
"mondayClose": "22:00",
"tuesdayEnabled": true,
"tuesday24Hours": false,
"tuesdayOpen": "09:00",
"tuesdayClose": "22:00",
"wednesdayEnabled": true,
"wednesday24Hours": false,
"wednesdayOpen": "09:00",
"wednesdayClose": "22:00",
"thursdayEnabled": true,
"thursday24Hours": false,
"thursdayOpen": "09:00",
"thursdayClose": "22:00",
"fridayEnabled": true,
"friday24Hours": false,
"fridayOpen": "09:00",
"fridayClose": "23:00",
"saturdayEnabled": true,
"saturday24Hours": false,
"saturdayOpen": "10:00",
"saturdayClose": "23:00",
"sundayEnabled": false,
"sunday24Hours": false,
"sundayOpen": null,
"sundayClose": null
}
```'
parameters:
- name: storefrontId
in: path
description: The storefront ID of the deal.
required: true
style: simple
schema:
type: string
format: uuid
- name: billboardId
in: path
description: The billboard ID of the deal.
required: true
style: simple
schema:
type: string
format: uuid
- name: isFromAd
in: query
description: Pass `true` if the user navigated here from an ad impression.
style: form
schema:
type: boolean
responses:
'200':
description: Full deal details including storefront hours.
content:
text/plain:
schema:
$ref: '#/components/schemas/DealResponseDetails'
application/json:
schema:
$ref: '#/components/schemas/DealResponseDetails'
text/json:
schema:
$ref: '#/components/schemas/DealResponseDetails'
operationId: getBusinessDealByStorefrontIdByBillboardId
x-operation-id-source: derived
components:
schemas:
DealResponse:
type: object
properties:
accountId:
type: string
format: uuid
billboardId:
type: string
format: uuid
storefrontId:
type: string
format: uuid
title:
type:
- string
- 'null'
description:
type:
- string
- 'null'
created:
type: string
format: date-time
updated:
type: string
format: date-time
configureStart:
type: boolean
start:
type:
- string
- 'null'
configureEnd:
type: boolean
end:
type:
- string
- 'null'
storefrontName:
type:
- string
- 'null'
locationDescription:
type:
- string
- 'null'
locationLat:
type: number
format: float
locationLng:
type: number
format: float
altitudeMeters:
type:
- number
- 'null'
format: float
categoryId:
type: string
format: uuid
isFavorited:
type: boolean
isReported:
type: boolean
storefrontImageId:
type:
- string
- 'null'
billboardImageId:
type:
- string
- 'null'
billboardVideoId:
type:
- string
- 'null'
isEnabled:
type: boolean
isFeatured:
type: boolean
unfeatureAt:
type:
- string
- 'null'
format: date-time
publicApi:
type: boolean
additionalProperties: false
QuickUpdateDealRequest:
required:
- description
- fridayEnabled
- locationDescription
- locationLat
- locationLng
- mondayEnabled
- name
- saturdayEnabled
- sundayEnabled
- thursdayEnabled
- title
- tuesdayEnabled
- wednesdayEnabled
type: object
properties:
title:
maxLength: 18
minLength: 1
type: string
description:
maxLength: 1000
minLength: 1
type: string
imageId:
type:
- string
- 'null'
videoId:
type:
- string
- 'null'
name:
minLength: 1
type: string
locationId:
type:
- string
- 'null'
locationDescription:
minLength: 1
type: string
locationLat:
type: number
format: float
locationLng:
type: number
format: float
altitudeMeters:
maximum: 1000
minimum: 0
type:
- number
- 'null'
format: float
categoryId:
type:
- string
- 'null'
format: uuid
mondayEnabled:
type: boolean
monday24Hours:
type: boolean
mondayOpen:
pattern: ^\d{2}:\d{2}$
type:
- string
- 'null'
mondayClose:
pattern: ^\d{2}:\d{2}$
type:
- string
- 'null'
tuesdayEnabled:
type: boolean
tuesday24Hours:
type: boolean
tuesdayOpen:
pattern: ^\d{2}:\d{2}$
type:
- string
- 'null'
tuesdayClose:
pattern: ^\d{2}:\d{2}$
type:
- string
- 'null'
wednesdayEnabled:
type: boolean
wednesday24Hours:
type: boolean
wednesdayOpen:
pattern: ^\d{2}:\d{2}$
type:
- string
- 'null'
wednesdayClose:
pattern: ^\d{2}:\d{2}$
type:
- string
- 'null'
thursdayEnabled:
type: boolean
thursday24Hours:
type: boolean
thursdayOpen:
pattern: ^\d{2}:\d{2}$
type:
- string
- 'null'
thursdayClose:
pattern: ^\d{2}:\d{2}$
type:
- string
- 'null'
fridayEnabled:
type: boolean
friday24Hours:
type: boolean
fridayOpen:
pattern: ^\d{2}:\d{2}$
type:
- string
- 'null'
fridayClose:
pattern: ^\d{2}:\d{2}$
type:
- string
- 'null'
saturdayEnabled:
type: boolean
saturday24Hours:
type: boolean
saturdayOpen:
pattern: ^\d{2}:\d{2}$
type:
- string
- 'null'
saturdayClose:
pattern: ^\d{2}:\d{2}$
type:
- string
- 'null'
sundayEnabled:
type: boolean
sunday24Hours:
type: boolean
sundayOpen:
pattern: ^\d{2}:\d{2}$
type:
- string
- 'null'
sundayClose:
pattern: ^\d{2}:\d{2}$
type:
- string
- 'null'
isEnabled:
type: boolean
isFeatured:
type: boolean
unfeatureAt:
type:
- string
- 'null'
format: date-time
additionalProperties: false
DealResponseDetails:
type: object
properties:
accountId:
type: string
format: uuid
billboardId:
type: string
format: uuid
storefrontId:
type: string
format: uuid
title:
type:
- string
- 'null'
description:
type:
- string
- 'null'
created:
type: string
format: date-time
updated:
type: string
format: date-time
configureStart:
type: boolean
start:
type:
- string
- 'null'
configureEnd:
type: boolean
end:
type:
- string
- 'null'
storefrontName:
type:
- string
- 'null'
locationDescription:
type:
- string
- 'null'
locationLat:
type: number
format: float
locationLng:
type: number
format: float
altitudeMeters:
type:
- number
- 'null'
format: float
categoryId:
type: string
format: uuid
isFavorited:
type: boolean
isReported:
type: boolean
storefrontImageId:
type:
- string
- 'null'
billboardImageId:
type:
- string
- 'null'
billboardVideoId:
type:
- string
- 'null'
isEnabled:
type: boolean
isFeatured:
type: boolean
unfeatureAt:
type:
- string
- 'null'
format: date-time
publicApi:
type: boolean
mondayEnabled:
type: boolean
monday24Hours:
type: boolean
mondayOpen:
type:
- string
- 'null'
mondayClose:
type:
- string
- 'null'
tuesdayEnabled:
type: boolean
tuesday24Hours:
type: boolean
tuesdayOpen:
type:
- string
- 'null'
tuesdayClose:
type:
- string
- 'null'
wednesdayEnabled:
type: boolean
wednesday24Hours:
type: boolean
wednesdayOpen:
type:
- string
- 'null'
wednesdayClose:
type:
- string
- 'null'
thursdayEnabled:
type: boolean
thursday24Hours:
type: boolean
thursdayOpen:
type:
- string
- 'null'
thursdayClose:
type:
- string
- 'null'
fridayEnabled:
type: boolean
friday24Hours:
type: boolean
fridayOpen:
type:
- string
- 'null'
fridayClose:
type:
- string
- 'null'
saturdayEnabled:
type: boolean
saturday24Hours:
type: boolean
saturdayOpen:
type:
- string
- 'null'
saturdayClose:
type:
- string
- 'null'
sundayEnabled:
type: boolean
sunday24Hours:
type: boolean
sundayOpen:
type:
- string
- 'null'
sundayClose:
type:
- string
- 'null'
additionalProperties: false
StorefrontCategoryResponse:
type: object
properties:
id:
type: string
format: uuid
name:
type:
- string
- 'null'
isActive:
type: boolean
additionalProperties: false
securitySchemes:
ApiKey:
type: apiKey
name: X-Api-Key
in: header