BonfireHub APIvictoria.bonfirehub.ca ↗
Access open public procurement opportunities from the City of Victoria's BonfireHub portal. Returns titles, closing dates, status, and more via one endpoint.
What is the BonfireHub API?
The Victoria BonfireHub API exposes 1 endpoint — list_open_opportunities — that returns all currently open public procurement opportunities published on the City of Victoria purchasing portal. Each record includes at least 7 response fields: opportunity_id, reference_number, title, status, closing_date, closing_date_utc, days_left, and more. Results are sorted by closing date ascending, matching the portal's default order, and support local pagination via page and page_size parameters.
curl -X GET 'https://api.parse.bot/scraper/bf1b66b0-0174-4d58-ab70-b41b96ed1a68/list_open_opportunities?page=2&page_size=2' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace victoria-bonfirehub-ca-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""Walkthrough: City of Victoria procurement portal — list open opportunities."""
from parse_apis.victoria_bonfirehub_ca_api import VictoriaProcurement, InputFormatInvalid
client = VictoriaProcurement()
# Browse the first few open procurement opportunities, sorted by closing date.
for opp in client.opportunities.list(page_size=10, limit=5):
print(f"{opp.reference_number}: {opp.title} — closes {opp.closing_date} ({opp.days_left}d left)")
# Drill into the earliest-closing opportunity for its detail URL.
try:
soonest = client.opportunities.list(page_size=5, limit=1).first()
except InputFormatInvalid as e:
print(f"Bad request: {e.message}")
soonest = None
if soonest is not None:
print(f"\nSoonest closing: {soonest.title}")
print(f" Status: {soonest.status}")
print(f" Detail: {soonest.detail_url}")
print(f" Department ID: {soonest.department_id}")
print("\nexercised: opportunities.list")
Returns the opportunities currently listed under the portal's Open Public Opportunities tab, one row per opportunity, sorted by closing date ascending (the portal's default order). The whole open list is fetched in one request and paged locally with page and page_size; omitting them returns the first 25 rows, and page_size is capped at 100. total_count is always the size of the whole open list (typically a few dozen at most), so a page whose first row index exceeds total_count returns an empty opportunities array with has_more false — for example, with 12 open opportunities, page 2 at page_size 25 is empty while page 2 at page_size 2 returns rows 3-4. Each row carries the opportunity id, reference number, title, status label as the portal computes it (Open, Reopened, Closed, Awarded or Cancelled), the closing date both in the portal's Pacific time zone and in UTC, whole days left until close (0 once under a day), the posting department id and the public detail page URL. Category, posted date and full detail-page content (description, contacts, documents, addenda) are not part of the list data and are not returned. An empty opportunities array with total_count 0 means the portal currently lists nothing open.
| Param | Type | Description |
|---|---|---|
| page | integer | 1-based page number over the locally paged open list. A page beyond the last one returns an empty opportunities array; use total_count and page_size to know how many pages exist. |
| page_size | integer | Rows per page; values above 100 are clamped to 100. |
{
"type": "object",
"fields": {
"page": "integer: page returned",
"has_more": "boolean: whether a further page exists",
"page_size": "integer: effective page size after clamping",
"total_count": "integer: number of opportunities in the portal's open list across all pages",
"opportunities": "array of open opportunity summaries (opportunity_id, reference_number, title, status, closing_date, closing_date_utc, days_left, department_id, detail_url); empty when page is past the last page"
},
"sample": {
"data": {
"page": 2,
"has_more": true,
"page_size": 5,
"total_count": 12,
"opportunities": [
{
"title": "Consulting Services for Retaining Wall Rehabilitation",
"status": "Open",
"days_left": 11,
"detail_url": "https://victoria.bonfirehub.ca/opportunities/111578",
"closing_date": "2026-10-13T16:00:00-07:00",
"department_id": "136",
"opportunity_id": "111578",
"closing_date_utc": "2026-10-13T23:00:00Z",
"reference_number": "RFP 26-092"
}
]
},
"status": "success"
}
}About the BonfireHub API
What the API Returns
The list_open_opportunities endpoint returns a paginated snapshot of every opportunity currently listed under the City of Victoria's Open Public Opportunities tab on the BonfireHub portal. Each opportunity object includes opportunity_id, reference_number, title, status, closing_date, closing_date_utc, days_left, and additional summary fields. The response envelope always includes total_count, page, page_size, and has_more so you can iterate through the full list programmatically.
Pagination Behavior
The full open list is fetched in a single request and paged locally. Use the page parameter (1-based) and page_size to control how many rows you receive per call. page_size values above 100 are clamped to 100. Check has_more to determine whether additional pages remain, and use total_count to calculate how many pages you need before making your first request.
Sorting and Freshness
Results are returned in closing-date ascending order — the same default the portal uses — so the most urgently closing opportunities appear first. Because the endpoint reflects the portal's live open list, the data represents current open opportunities at the time of the request. Opportunities that have closed, been cancelled, or are not yet published will not appear in the response.
The BonfireHub API is a managed, monitored endpoint for victoria.bonfirehub.ca — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when victoria.bonfirehub.ca changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official victoria.bonfirehub.ca API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Monitor the City of Victoria's active RFPs and tenders by polling
closing_dateanddays_leftfields to send deadline alerts - Build a procurement calendar that aggregates
closing_date_utcvalues for bid scheduling - Track
statuschanges across open opportunities to detect newly published or updated tenders - Index
titleandreference_numberfields for a searchable internal procurement database - Feed
total_countanddays_leftinto a dashboard showing how many Victoria opportunities close within the next 7 days - Automate vendor qualification workflows by filtering opportunities whose
closing_datefalls within a configurable window
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 200 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
| Team | $300/mo | 20,000 | 300 req/min |
| Company | $1,000/mo | 100,000 | 500 req/min |
Each endpoint has a fixed posted price per successful call — most fall between 1 and 10 credits — shown on this API's page before you run it. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does victoria.bonfirehub.ca have an official developer API?+
What does the `list_open_opportunities` endpoint actually return for each opportunity?+
opportunities array includes opportunity_id, reference_number, title, status, closing_date, closing_date_utc, and days_left, plus additional summary fields. The response envelope provides total_count, page, page_size, and has_more for pagination.Does the API return closed, awarded, or historical opportunities?+
Can I filter opportunities by category, department, or keyword through the API?+
list_open_opportunities endpoint does not accept filter parameters — it returns the full open list and supports only page and page_size for pagination. Filtering by title keyword or other fields must be done client-side after receiving the response. You can fork this API on Parse and revise it to add server-side filter parameters if the portal exposes that capability.