Gnb APInbon-rpanb.gnb.ca ↗
Access open public procurement tenders and notices from New Brunswick's NBON via 2 endpoints. List all open opportunities and fetch full notice details by control number.
What is the Gnb API?
The NBON API covers New Brunswick's public procurement portal through 2 endpoints, returning paginated lists of currently open tenders and notices plus full notice details for each. The list_open_opportunities endpoint surfaces up to 30 rows per page ordered by closing date, while get_opportunity returns the complete public notice — including commodities, contact details, and closing timestamps — for any individual opportunity identified by its control number.
curl -X GET 'https://api.parse.bot/scraper/e88d5acc-7dbd-48ce-b083-43f5340fc2c9/list_open_opportunities?page=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 nbon-rpanb-gnb-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: NBON SDK — browse open NB procurement opportunities and read full notices."""
from parse_apis.nbon_rpanb_gnb_ca_api import NBON, OpportunityNotFound
client = NBON()
# Browse the first few open opportunities (soonest closing first).
for summary in client.opportunity_summaries.list(limit=5):
print(summary.title, "|", summary.closing_date, "|", summary.organization)
# Drill into the first opportunity for its full notice.
summary = client.opportunity_summaries.list(limit=1).first()
if summary is not None:
# Navigate from summary to full detail via the typed relationship.
opp = summary.details()
print(opp.title)
print("Issued:", opp.date_issued, "| Closing:", opp.closing_date)
print("Organization:", opp.organization)
print("Submission:", opp.submission_note)
if opp.commodities:
print("Commodities:", ", ".join(opp.commodities))
# Same opportunity via direct point-lookup using the discovered key.
try:
same = client.opportunities.get(control_number=opp.control_number)
print("Fetched by key:", same.title, "| Amendments:", same.amendment_number)
except OpportunityNotFound as e:
print("Not found:", e.control_number)
print("exercised: opportunity_summaries.list / summary.details / opportunities.get")
Lists the opportunities currently open on NBON, one row per opportunity in the site's order (soonest closing first), in fixed pages of 30 rows; `page` selects the page (omitted = first page). Without `contract_type` the rows come from the site's 'All Open Opportunities' page and `total` is the site's own count of open opportunities (page count = ceil(total/30)). With `contract_type` the rows come from NBON's Advanced Search restricted to open documents whose document number starts with that code (matched by the site, case-insensitively, e.g. 'RFP' matches 'RFP26-051'); that search returns no total, so `total` is null and `has_more` is derived by asking the site for one extra row. NBON has no explicit solicitation-type field, so this filter only reaches documents whose issuer encodes the type in the number (RFP, RFQ, RFI, RFEOI, ...); purely numeric tender numbers are never matched. A page past the last one, or a prefix matching nothing, returns an empty `opportunities` list with `has_more` false. `version` is the amendment/version number shown for the row and is null when the site shows none. `control_number` is the site's internal document id that get_opportunity accepts. `source_url` is the notice's URL exactly as the site links it; NBON binds it to the browsing session that produced this response and offers no permanent public link, so treat it as provenance and use get_opportunity to read the notice. `include_details=true` additionally fetches the full get_opportunity notice for every row of the page (up to 30 extra site requests, several seconds): each row gains `details` (the get_opportunity payload, or null) and `details_error` (null, or 'not_found' | 'site_error' | 'upstream_error' | 'extraction_failed'), and the response gains `details_fetched` and `details_failed` (control numbers whose notice could not be read). Dates are yyyy/mm/dd HH:MM strings in Atlantic Time as displayed by the site. A call costs three site requests (four with contract_type) plus one per row when include_details is true.
| Param | Type | Description |
|---|---|---|
| page | integer | 1-based page number of 30 opportunities each. |
| contract_type | string | Document-number prefix the site matches case-insensitively at the start of the document number (1-30 letters, digits, spaces, '.', '_', '/', '-'), e.g. RFP, RFQ, RFI, RFEOI. Omitted = all open opportunities. |
| include_details | boolean | When true, embed the full get_opportunity notice in each row as `details` (one extra site request per row). |
{
"type": "object",
"fields": {
"page": "requested page number",
"total": "integer count of open opportunities reported by the site (unfiltered mode); null when contract_type is given or the page is beyond the end",
"has_more": "true when a later page exists",
"page_size": "rows per page (always 30, fixed by the site)",
"contract_type": "the document-number prefix applied by the site, or null when unfiltered",
"opportunities": "array of opportunity rows: control_number (string id for get_opportunity), document_number (public tender/notice number), title, organization, published_date, closing_date, version (integer or null), attachments_exist / qa_exists / interested_exists / awards_exist (booleans from the row's detail indicators), document_type (e.g. 'Invitation to Tender' or 'Advertisement'), source_url (session-bound notice URL as linked by the site); with include_details=true also details (get_opportunity payload or null) and details_error (null or a failure code)",
"details_failed": "only with include_details=true: control numbers whose notice could not be read",
"details_fetched": "only with include_details=true: number of rows whose notice was read"
},
"sample": {
"data": {
"page": 1,
"total": null,
"has_more": false,
"page_size": 30,
"contract_type": "RFP",
"opportunities": [
{
"title": "HEATING SYSTEM MODERNIZATION - MONCTON CO",
"details": {
"title": "HEATING SYSTEM MODERNIZATION - MONCTON CO",
"details": "The City of Moncton is seeking proposals from qualified professional consulting firms ...",
"time_zone": "Atlantic Time",
"source_url": "https://nbon-rpanb.gnb.ca/showDisplayDocument?sessionID=REDACTED_SESSION&disID=18602090&doc_search_by=Tend&fromSearchScreen=Y",
"commodities": [
"ENGINEERING SERVICES"
],
"contact_fax": "+1 (555) 012-3456",
"date_issued": "2026/09/08",
"expiry_date": null,
"status_note": null,
"closing_date": "2026/10/06 15:00:00",
"contact_name": "John Doe",
"organization": "MU, CITY OF MONCTON",
"publish_date": "2026/09/08 15:17:57",
"contact_email": "[email protected]",
"contact_phone": "+1 (555) 012-3456",
"delivery_date": null,
"document_kind": "Tender Notice",
"document_type": "Advertisement",
"control_number": "18602090",
"document_class": "Notice",
"effective_date": null,
"document_number": "RFP26-051",
"submission_note": "The solicitation document will contain the instructions on how, when and where to submit your bids.",
"amendment_number": null,
"shipping_address": [],
"attachments_exist": false,
"issuing_agency_address": [
"MU, CITY OF MONCTON",
"City of Moncton",
"Purchasing Department",
"655 Main Street, 4th Floor",
"MONCTON, New Brunswick",
"E1C 1E8"
]
},
"version": null,
"qa_exists": false,
"source_url": "https://nbon-rpanb.gnb.ca/showDisplayDocument?sessionID=REDACTED_SESSION&disID=18602090&doc_search_by=Tend&fromSearchScreen=Y",
"awards_exist": false,
"closing_date": "2026/10/06 15:00",
"organization": "MU, CITY OF MONCTON",
"details_error": null,
"document_type": "Advertisement",
"control_number": "18602090",
"published_date": "2026/09/08 15:17",
"document_number": "RFP26-051",
"attachments_exist": false,
"interested_exists": false
}
],
"details_failed": [],
"details_fetched": 1
},
"status": "success"
}
}About the Gnb API
Browsing Open Opportunities
The list_open_opportunities endpoint returns a paginated list of all currently open procurement opportunities published on the New Brunswick Opportunities Network. Each page contains up to 30 rows, fixed by the source site. Responses include a total count of open opportunities as reported by the site, a has_more flag indicating whether additional pages exist, and an opportunities array. Each row carries a control_number (used to retrieve the full notice), a document_number (the public tender or notice reference), and a title. The optional page parameter is 1-based; omitting it returns the first page. When requesting a page beyond the last, total is null.
Full Notice Detail
The get_opportunity endpoint accepts a control_number exactly as returned by list_open_opportunities and returns the complete public notice. Two document types are served: Invitation to Tender (document_class: 'Tender') and a Notice or advertisement (document_class: 'Notice'). Response fields include title, details (the full notice body as plain text), date_issued and closing_date (both in yyyy/mm/dd format, closing date with time), time_zone, commodities (an array of bid-matching category names), contact_name, contact_fax, and optional fields expiry_date and status_note (present when the site shows a status banner such as a withdrawal notice).
Coverage and Scope
This API covers only currently open opportunities — the live browse page on NBON. Closed, awarded, or historical opportunities are not returned. The status_note field on get_opportunity can surface withdrawal or amendment banners when the source displays them, which is useful for detecting notices that have changed status since they were first listed.
The Gnb API is a managed, monitored endpoint for nbon-rpanb.gnb.ca — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when nbon-rpanb.gnb.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 nbon-rpanb.gnb.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 new tenders in specific commodity categories using the
commoditiesfield fromget_opportunity - Build a closing-deadline alert system using
closing_dateandtime_zonefrom full notices - Aggregate open New Brunswick procurement opportunities into a unified vendor dashboard
- Filter tenders by issuing contact organization using
contact_namefrom notice detail - Track tender volume over time using the
totalcount returned bylist_open_opportunities - Detect withdrawn or amended notices by checking the
status_notefield on individual opportunities - Cross-reference public
document_numbervalues against internal procurement tracking systems
| 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 the New Brunswick Opportunities Network have an official developer API?+
What does `list_open_opportunities` return for each row, and how does pagination work?+
opportunities array includes a control_number, document_number, and title. Pages are fixed at 30 rows each, ordered by soonest closing date first. Use the integer page parameter (1-based) to navigate. The has_more field tells you whether another page follows, and total gives the site's own count of all currently open opportunities. When you request a page past the end, total returns null.Are closed, awarded, or historical opportunities available through this API?+
What is the difference between a Tender and a Notice in `get_opportunity` responses?+
document_class field distinguishes the two templates NBON uses. A value of 'Tender' indicates an Invitation to Tender with structured procurement fields. A value of 'Notice' indicates a general advertisement or public notice. Both share the same core response shape including details, closing_date, commodities, and contact_name.Does the API support filtering opportunities by commodity category or issuing department?+
list_open_opportunities returns all open opportunities in closing-date order without filter parameters; commodity and contact data are only available after fetching individual notices via get_opportunity. You can fork this API on Parse and revise it to add filtered listing endpoints using the commodity or organization values exposed in the detail response.