API Technical Documentation
Introduction
The Business Intelligence API is designed to allow querying of notice, award and spend data. This document will guide you on how to create your API key, how to authenticate with the API, and how to then use this authentication token to fetch data. It also explains the results budget that applies to your organisation, and how search results are paged.
Changes in this edition (September 2026)
If you integrated against an earlier edition of this document, these are the changes that affect existing code:
- The daily allowance is now a results budget. The limit of 10 calls per day has been replaced by 100,000 results per organisation per rolling 24 hours, shared across all endpoints and access tokens. See “Results Budget”.
- Search responses are paged at 1,000 rows. A search that previously returned up to 10,000 rows in one response now returns the first 1,000 by default and reports “totalPages”; request further pages with “pageNo”. A request with pageSize above 1,000 is rejected with 400. See “Paging”.
- Notice and award search rows carry more fields. Each row now includes the full description, publication reference, awarding-authority contact and address, CPV codes, region codes, sectors and a framework-agreement flag, so a listing can be read without a detail call per row. See “API Schema”.
- New response headers. X-Quota-Limit, X-Quota-Remaining and X-Quota-Reset replace X-Rate-Limit-Remaining on every response; a 429 carries Retry-After.
Sandbox
A sandbox environment has been created that allows you to test out your connections to the service, without using any of your organisation’s results budget. This should be used just to verify that you can successfully generate authentication tokens, and to make calls to the API endpoints and receive successful responses.
Please note, the endpoints in the sandbox are built to return stubbed data. These values are mocked and always return the same regardless of the criteria provided in a request. Sandbox search responses contain a small fixed number of rows, so they are not representative of the volume the live API returns.
When testing against the sandbox, please use the following urls:
Authentication: https://sandbox.oidc.bipintelligence.com/.well-known/openid-configuration
API: https://sandbox.bipintelligence.com/open-api/v3/api-docs
The sandbox does not require you to configure an API client key and secret for your account via the BI Platform site. When using the sandbox, you can skip the “Access Token Setup” section in this guide, and instead use the below common client key and secret to generate authentication tokens:
Key: open-api-sandbox
Secret: open-api-sandbox-secret
API Technical Documentation – Live API
Access Token Setup
Access token setup must be performed by the Primary or Admin user for your organisation’s account in the BI Platform by navigating to the “Open API” page.
In this page, you will initially be presented with an empty table of access tokens, and can create one by selecting “Generate Token”. In this form, you can select which data your access token should be permitted to query, and optionally provide a list of IP addresses that are allowed to make calls with this access token. There is no limit on the number of IP addresses that can be entered here.
Selecting “Submit” will then present your API Client ID and Secret. Please take note of these details immediately, as the Secret cannot be viewed again after this, and would require the regeneration of your Access Token.
Successfully generated tokens are then viewable within this page, allowing you to edit the IP Addresses and endpoints you wish to allow access to, as well as regenerating tokens before they expire.
Authentication
The API uses the OAuth2 standard for authentication and authorization. Authentication tokens should be created using the “client_credentials” grant type and one or more of the following scopes, which you should have permitted the token to use in the “Open API” management page in the BI site:
- OPENAPI_NOTICES
- OPENAPI_AWARDS
- OPENAPI_SPEND
Token requests should be made to https://oidc.bipintelligence.com/oauth2/token, eg in unix:
curl --location 'https://oidc.bipintelligence.com/oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --header 'Authorization: Basic <CLIENT_ID:CLIENT_SECRET>' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'scope=OPENAPI_NOTICES OPENAPI_AWARDS'
Or in Windows:
curl.exe -L "https://oidc.bipintelligence.com/oauth2/token" ^ -H "Content-Type: application/x-www-form-urlencoded" ^ -u "CLIENT_ID:CLIENT_SECRET" ^ --data-urlencode "grant_type=client_credentials" ^ --data-urlencode "scope=OPENAPI_NOTICES OPENAPI_AWARDS"
You should ensure that <CLIENT_ID>:<CLIENT_SECRET> is encoded in Base 64. This will give a response similar to:
{
"access_token": "Your token here",
"scope": "OPENAPI_AWARDS OPENAPI_NOTICES",
"token_type": "Bearer",
"expires_in": 899
}
The “access_token” value from the above response should then be passed as a Bearer token in any request to the API. Access Tokens are valid for 15 minutes before they need to be regenerated.
API Technical Documentation – API Requests
Open API Spec/Swagger
The full API specification can be found at https://app.bipintelligence.com/open-api/v3/api-docs as well as a Swagger UI at https://app.bipintelligence.com/open-api/swagger-ui/index.html. These can be used for a full reference of the fields that can be used for searching each dataset, and for details on the fields returned. Please note, when using the Swagger UI, the Bearer Authentication token must be set using the steps mentioned in the “Authentication” section above.
Results Budget
Open API Core organisations have a budget of 100,000 results per 24 hours, shared across every access token and every endpoint the organisation uses. The 24-hour window starts with your organisation’s first call and renews 24 hours later; it is not aligned to midnight.
Each call costs the number of rows it returns, with a minimum cost of 1:
- A search (/notices, /awards, /spend/transactions) costs one result per row returned. A page of 1,000 rows costs 1,000; a search that matches nothing costs 1.
- A detail request (/notices/{id}, /awards/{id}) costs 1.
- A buyer or supplier list request (/spend/buyers, /spend/suppliers) costs one result per name returned.
- A call that fails (for example a 400, 401 or 403 response) costs nothing.
If a call would return more rows than you have left, the response is trimmed to the remaining rows so that the last of your budget is not wasted: “totalResults” still reports the full number of matches, but “results” holds only what could be afforded. Once the budget is exhausted, every call returns 429 until the window renews.
Every authenticated response carries three headers so you can track your position without a separate call:
| Header | Meaning |
|---|---|
| X-Quota-Limit | Your organisation’s budget for the window (100000) |
| X-Quota-Remaining | Results left in the current window, after this call |
| X-Quota-Reset | The time (ISO 8601, UTC) at which the window renews and the budget returns to its full value |
A 429 response additionally carries a “Retry-After” header with the number of seconds until the window renews. Open API Pro organisations have no budget; their responses report “unlimited” in X-Quota-Limit and X-Quota-Remaining.
Paging
All search and list endpoints are paged. Two optional query parameters control the page:
| Parameter | Default | Allowed | Description |
|---|---|---|---|
| pageNo | 1 | 1 or greater | The page to return, counting from 1 |
| pageSize | 1000 | 1 to 1000 | The number of rows per page |
Every paged response returns the same envelope:
| Field | Type | Description |
|---|---|---|
| totalResults | Long | Total number of matches for the request, across all pages |
| totalPages | Long | Number of pages that can be requested at this pageSize |
| pageNo | Integer | The page returned |
| pageSize | Integer | The page size applied |
| results | Object[] | The rows on this page |
Notice and award searches can reach at most the first 10,000 matches of any search: pageNo × pageSize may not exceed 10,000, so at the default page size pages 1 to 10 are available and “totalPages” never reports more than 10. If a search matches more than 10,000 notices or awards, narrow the criteria (for example a shorter published-date range) rather than paging further. Spend endpoints have no such ceiling.
A pageNo of 0 or below, a pageSize outside 1 to 1000, or a page beyond the last one available returns 400 with an “errorMessage” explaining which limit was crossed.
Search endpoints also accept “sortBy” and “sortDirection” (ASC or DESC) query parameters. The sortBy values for each endpoint are:
- /notices: NOTICE_ID, TITLE, BUYER_NAME, VALUE, CURRENCY, COUNTRY_CODE, PUBLISHED_DATE, CONTRACT_START_DATE, CONTRACT_END_DATE
- /awards: AWARD_ID, TITLE, BUYER_NAME, SUPPLIER_NAME, VALUE, CURRENCY, COUNTRY_CODE, PUBLISHED_DATE, CONTRACT_START_DATE, CONTRACT_END_DATE
- /spend/transactions: BUYER_NAME, SUPPLIER_NAME, TRANSACTION_NAME, AMOUNT, TRANSACTION_DATE, INDUSTRY, REGION
Use a stable sort (for example PUBLISHED_DATE) when walking through pages, so that rows do not move between pages while you are reading them.
Response Codes
There are 5 response codes you should expect when making requests to the API:
- 200, your request was successful, and data was returned.
- 400, the request could not be processed: invalid search criteria, or a paging parameter outside the limits described above. The response body’s “errorMessage” states the reason.
- 401, you are unauthorized to call this endpoint (e.g. due to an Expired Access Token, calling from an IP Address not configured for this token, or a token without the scope for that dataset).
- 403, the search criteria include a country outside your subscription’s coverage.
- 429, your organisation’s results budget for the current 24-hour window is used up (see “Results Budget” above). Wait for the time given in the Retry-After header.
Endpoints
API URL: https://app.bipintelligence.com/open-api
Notices
- /notices (POST) – search notice data using a given criteria. Paged.
- /notices/{id} (GET) – the detailed view of a notice.
Awards
- /awards (POST) – search award data using a given criteria. Paged.
- /awards/{id} (GET) – the detailed view of an award.
Spend
- /spend/buyers (GET) – the buyer names for which we hold spend data. Paged.
- /spend/suppliers (GET) – the supplier names for which we hold spend data. Paged.
- /spend/transactions (POST) – transactions for a given buyer/supplier name and a date range. Paged.
API Technical Documentation – API Schema
The paged envelope (totalResults, totalPages, pageNo, pageSize, results) is described under “Paging” above and is not repeated in each table below. Dates are returned as YYYY-MM-DD unless stated otherwise.
/notices
Each search row now carries the same descriptive fields as the detail view, so a listing can be read without a further request per notice. Only the contact name is detail-only.
| Field | Type | Description |
|---|---|---|
| results.id | Long | ID of the notice, used to view the full detail |
| results.title | String | Title of the contract |
| results.awardingAuthority | String | Name of the authority which published this notice |
| results.value | Double | Value of the tender notice |
| results.currency | String | Currency of the tender notice |
| results.country | String | Country in which the tender will take place |
| results.publishedDate | String | Date the notice was published |
| results.startDate | String | Date the tender will begin once awarded |
| results.endDate | String | Date the tender will end once awarded |
| results.deadlineDate | String | Deadline date for applications |
| results.cpvCodes | String[] | CPV codes which apply to this tender notice |
| results.regionCodes | String[] | NUTS region codes for the place of performance |
| results.sectors | String[] | Industry sectors derived from the CPV codes |
| results.frameworkAgreement | Boolean | Whether the notice establishes a framework agreement |
| results.description | String | Full description of the contract as published |
| results.referenceNumber | String | Publication reference (OJEU / Find a Tender); null where the source has none |
| results.location | String | Town of the awarding authority |
| results.contact | Object | Primary contact we hold for this tender notice |
| results.contact.contactName | String | Always null on search rows; available from /notices/{id} |
| results.contact.contactPhoneNumber | String | Telephone number of the contact |
| results.contact.email | String | Email of the contact |
| results.address | Object | Object holding address details for this authority |
| results.address.address | String | Address of the authority |
| results.address.town | String | Town of the authority |
| results.address.postCode | String | Post code of the authority |
/awards
| Field | Type | Description |
|---|---|---|
| results.id | Long | ID of the award, used to view the full detail |
| results.title | String | Title of the awarded contract |
| results.awardingAuthority | String | Name of the authority which published this award |
| results.suppliers | String[] | List of the suppliers the tender was awarded to |
| results.value | Double | Value of the tender award |
| results.currency | String | Currency of the tender award |
| results.country | String | Country in which the award will take place |
| results.publishedDate | String | Date the award was published |
| results.startDate | String | Date the awarded tender will begin |
| results.endDate | String | Date the awarded tender will end |
| results.cpvCodes | String[] | CPV codes which apply to this tender award |
| results.regionCodes | String[] | NUTS region codes for the place of performance |
| results.sectors | String[] | Industry sectors derived from the CPV codes |
| results.frameworkAgreement | Boolean | Whether the award is made under a framework agreement |
| results.description | String | Full description of the contract as published |
| results.referenceNumber | String | Publication reference (OJEU / Find a Tender); null where the source has none |
| results.location | String | Town of the awarding authority |
| results.contact | Object | Primary contact we hold for this tender award |
| results.contact.contactName | String | Always null on search rows; available from /awards/{id} |
| results.contact.contactPhoneNumber | String | Telephone number of the contact |
| results.contact.email | String | Email of the contact |
| results.address | Object | Object holding address details for this authority |
| results.address.address | String | Address of the authority |
| results.address.town | String | Town of the authority |
| results.address.postCode | String | Post code of the authority |
/notices/{id}
| Field | Type | Description |
|---|---|---|
| apiContractNoticeDetail | Object | Object holding the notice details |
| apiContractNoticeDetail.id | Long | ID of the notice |
| apiContractNoticeDetail.title | String | Title of the contract |
| apiContractNoticeDetail.description | String | Full description of the contract as published |
| apiContractNoticeDetail.location | String | Location of the contract to be performed |
| apiContractNoticeDetail.value | Double | Value of the tender notice |
| apiContractNoticeDetail.publishedDate | String | Date and time the notice was published (YYYY-MM-DDTHH:MM:SS) |
| apiContractNoticeDetail.cpvCodes | String | CPV codes which apply to this tender notice |
| apiContractNoticeDetail.contact | Object | Primary contact we hold for this tender notice |
| apiContractNoticeDetail.contact.contactName | String | Name of the contact |
| apiContractNoticeDetail.contact.contactPhoneNumber | String | Telephone number of the contact |
| apiContractNoticeDetail.contact.email | String | Email of the contact |
| apiContractNoticeDetail.awardingAuthority | String | Name of the authority which published this notice |
| apiContractNoticeDetail.address | Object | Object holding address details for this authority |
| apiContractNoticeDetail.address.address | String | Address of the authority |
| apiContractNoticeDetail.address.town | String | Town of the authority |
| apiContractNoticeDetail.address.postCode | String | Post code of the authority |
| apiContractNoticeDetail.referenceNumber | String | Reference number for this tender notice |
| apiContractNoticeDetail.deadlineDate | String | Deadline date for applications |
/awards/{id}
| Field | Type | Description |
|---|---|---|
| apiAwardDetails | Object | Object holding the award details |
| apiAwardDetails.id | Long | ID of the award |
| apiAwardDetails.title | String | Title of the contract |
| apiAwardDetails.description | String | Full description of the contract as published |
| apiAwardDetails.location | String | Location of the contract to be performed |
| apiAwardDetails.value | Double | Value of the tender award |
| apiAwardDetails.publishedDate | String | Date and time the award was published (YYYY-MM-DDTHH:MM:SS) |
| apiAwardDetails.cpvCodes | String | CPV codes which apply to this tender award |
| apiAwardDetails.contact | Object | Primary contact we hold for this tender award |
| apiAwardDetails.contact.contactName | String | Name of the contact |
| apiAwardDetails.contact.contactPhoneNumber | String | Telephone number of the contact |
| apiAwardDetails.contact.email | String | Email of the contact |
| apiAwardDetails.awardingAuthority | String | Name of the authority which published this award |
| apiAwardDetails.address | Object | Object holding address details for this authority |
| apiAwardDetails.address.address | String | Address of the authority |
| apiAwardDetails.address.town | String | Town of the authority |
| apiAwardDetails.address.postCode | String | Post code of the authority |
| apiAwardDetails.referenceNumber | String | Reference number for this tender award |
| apiAwardDetails.startDate | String | Date the awarded contract begins |
| apiAwardDetails.endDate | String | Date the awarded contract ends |
| apiAwardDetails.suppliers | String[] | List of the suppliers the tender was awarded to |
/spend/buyers
| Field | Type | Description |
|---|---|---|
| results.organisationName | String | Name of the Buyer |
/spend/suppliers
| Field | Type | Description |
|---|---|---|
| results.organisationName | String | Name of the Supplier |
/spend/transactions
| Field | Type | Description |
|---|---|---|
| results.buyerName | String | Name of the Buyer |
| results.supplierName | String | Name of the Supplier |
| results.transactionName | String | Name of the Transaction |
| results.amount | Double | Value of the Transaction |
| results.transactionDate | String | Date recorded for the Transaction |
| results.industry | String | Industry of the Transaction |
| results.region | String | Region of the Transaction |