API documentation

A copy of API v3.0 - Documentation v2.1 - Summary Records on docs.openopps.com, last changed there on 30 October 2026. Plans and prices are on the developer portal.

Contents

Documentation API - Summary Records Endpoint (Version 3)

Created: 6 October 2026

Replaces: Documentation v2.0 (created 16 February 2026)

https://openopps.com

https://openopps.com/api/

https://openopps.com/pricing/#api-pricing/

Downloadable version.

api-v30-documentation-v21-summary-records.md 58334

Changes since v2.0

Version 2.1 clarifies how fields should be interpreted (dates and time zones, status, values, identifiers, duplicates and CPV scores), documents search and filtering behaviour, corrects field descriptions and limits, and removes references that are no longer accurate.

Spend Network's summary endpoint provides a simplified JSON output that provides a flatter, smaller, more consistent output. This enables lower volumes of data to travel into databases and more consistent and easier parsing of the data.

Guidance for developers, including LLM developers

Advice for teams working with our API. For teams using LLMs working with LLMs is fine, we do it and we're happy for our clients to do the same. Make sure you give the LLMs this information.

  • Be mindful of our publishing schedule - We publish new notices twice a day only. Typically at 6am and 11am GMT - this timing can vary depending on the volume of publishing. Don't all hit the API at precisely 6AM, you'll get queued. Use your brains, or whatever cognitive capacity you have to make a good decision.
  • Caching data - If you are caching data DO NOT set your script to poll the API on schedules between these times (e.g. every few minutes, you'll waste our resources and get NO NEW data).
  • Be respectful - New notices are published twice a day, so polling more often than that returns no new data. Collect once after each publishing run. Excessive use may get your account blocked temporarily or permanently, and we will not reimburse you if you lose access as a result. If you need more capacity, speak to us.
  • Download this documentation file and add it to your project - Make sure your LLM knows to reference the documents and that it is in the chat context when writing code to access the API and to parse results of notices.
  • Assume that completion is ragged - Every field other than the title, the augmented CPV codes and the published date are optional. Some have an award value, some have a range, some have nothing. Code like data.results[0].supplier.name with no guard throws on the first record from a sparse source, or silently produces wrong output. We try to populate as much as we can but the underlying data sometimes just doesn't exist.
  • Do not index into a nested field without a presence check, and do not assume a field that appeared in one record exists in the next. Write defensive accessors. Check for presence at every level of nesting. Treat a field that was populated in record 1 as entirely capable of being absent in record 2.
  • Do not guess field names - the field listing is here for a reason. Use it. Pattern-matching to what a procurement API "should" return is the most common single failure. Names like contract_value, deadline, cpv, and tender_id get written from prior expectation rather than from the actual schema. When the real names differ, the code either throws or returns undefined everywhere. Use the documented schema and the worked example responses. Do not infer field names from the domain.
  • Do not invent the status or category vocabulary - Release tags come from the published list in this document, not from a guess. Do not use tag_status to decide whether a notice is currently open: use tender_end_date.
  • Understand our maximums - You can receive no more than 10,000 documents in a single request. You can use limit values to cap the number of documents you will receive.
  • Pagination: get the terminating condition right - Do not grab the first page and stop. The API uses offset-based paging: increase offset by limit on each call and stop when a page returns fewer records than limit. A single query returns no more than 10,000 records.
  • Augmented CPVs - we provide five augmented CPVs for every document, each with a relevance score. Augmented codes are assigned at the four-digit group level (e.g. 34120000). CPV filtering matches publisher codes and augmented codes, so filtering on a group-level code reaches notices whose publisher gave no CPV, regardless of language or country. A filter on a more specific code (e.g. 34121000) matches publisher codes only. Because all five augmented codes are matched, use cpv_aug_threshold (0 to 100, the same scale as relevance_score) to exclude weak matches.
  • Search is relevance-ranked, not boolean keyword matching - Results are returned by relevance. A top result may not literally contain the query term. Do not "fix" this by post-filtering on string match, because that throws away the best results. Treat absence of a literal keyword match as expected behaviour, not a bug. Do not add string-match post-filtering on top of ranked results. When search_term__is is set, results are ordered by relevance and sort_by does not apply. In loose mode, use a wildcard to catch inflected forms: autobus* matches autobusy and autobusów, autobus does not.
  • Deduplicate across sources - Because the data is aggregated, the same underlying tender can appear from multiple portals, each with its own ocid. Set dedupe__is to true to remove the duplicates we have identified, using fuzzy matching and deterministic drift. Because we are cautious, you may still see what looks like a duplicate. Usually this is because a notice contains sufficient deviation in key areas (e.g. deadline date) between notices to warrant publishing both versions. result_count is counted before deduplication, so it can exceed the number of records you receive.
  • Handle rate limits and read the error body - Implement backoff rather than retrying immediately or not at all. Read the error response body, not just the HTTP status code, because useful detail is carried in the payload.
  • Expect non-ASCII text - With 160+ countries in scope, expect diacritics and non-Latin scripts in fields like buyer and supplier names. Handle Unicode correctly end to end so names are not mangled.

JSON Output Structure and Information Design Principles

The JSON output for the API has been meticulously structured to ensure clarity, consistency, and ease of use. The following key principles have been adopted in its design:

1. A single document structure for all records

  • Consistency: All records, whether tender notice, planning or contract awards contain the same fields and all fields deploy consistent data structures at all times. This ensures that simple validation routines can be written for each document (e.g. a checksum for the total number of fields).
  • Use: Tender documents will contain fields for awards data, which will not be populated, it is critical for developers to use release_tags to determine the nature of the published document before accessing the appropriate data.

2. Clear and Descriptive Naming Conventions

  • Consistency: Each key follows a consistent naming pattern that aids in easy identification and understanding. For example, all monetary values related to awards are prefixed with award_, making it straightforward to locate and differentiate from other values like tender_.
  • Descriptiveness: Keys are named descriptively to convey the precise information they hold. For instance, buyer_address_country_name clearly indicates it stores the country name of the buyer's address.
  • Categorisation: Related data points are grouped together logically. For example, all keys related to buyer information start with buyer_ (e.g., buyer_name, buyer_address_country_name), ensuring that similar information can be found in proximity.
  • Hierarchical Structure: Our data is broadly flat, but the small amount of hierarchy helps users navigate the data efficiently, recognizing patterns and relationships between different pieces of information.

4. Effective handling of one to many relationships

  • Managing edge cases: In rare cases contract award notices are published as an extension to a tender notice, in still rarer circumstances there are more than one award published against a given tender. We handle this dynamically, collating data where appropriate (e.g in the award_titles ) and using the first award found in fields where referential integrity is essential. This is the case in fields with the _first suffix.
  • Implications: In some cases it is possible that only the first award from a set of multiple awards is being documented. In this context developers can use our complete API to gather additional records from the original published releases where necessary.

5. Comprehensive Data Coverage

  • Detailed Information: The JSON structure includes extensive details covering various aspects such as buyer details, award values in multiple currencies, tender specifics, and more. This comprehensive coverage ensures users have all necessary data in one place.
  • Multiple Data Types: The structure accommodates various data types including strings, numbers, arrays, and booleans, to accurately represent different kinds of information.

6. Timestamp and Date Management

  • ISO 8601 Format: All date and time values are provided in ISO 8601 format (e.g., 2021-12-17T08:27:49Z), a widely accepted standard that supports interoperability and ease of parsing across different systems.
  • Time zones: date_created and date_updated are recorded in UTC, although they carry no offset in the output. Some source dates, including release_date and tender_end_date, are published without a time zone offset; do not assume these are UTC.
  • Clear Distinction Between Dates: Different types of dates such as release_date, start_date, and closing_date are clearly differentiated, ensuring precise tracking of timelines.

7. Nullability for Optional Fields

  • Explicit Nulls: Fields that might not always have a value (e.g., contact_url, buyer_address_street_address) are included with a null value when applicable, maintaining a consistent structure while signalling optional data.

8. Array Utilization for Multiple Entries

  • Lists for Multiple Items: Fields that can have multiple entries, such as supplier_names, cpv_names, and supplier_ids, are represented as arrays. This approach ensures flexibility and scalability in handling multiple values.

9. Identification and Referencing

  • Unique Identifiers: Keys like ocid and tender_id are used to provide unique identifiers for contracts and tenders, supporting traceability and integration with other datasets. Where we are able to we will supply identifiers for suppliers with a unique id for companies to reconcile to the source.
  • References: references_ocids lists other records that our matching process found similar to this one, each with a similarity score between 0 and 1. A listed record may be a different procurement by the same buyer, so treat it as a hint to investigate, not as a confirmed link.

10. Currency and Value Clarity

  • Explicit Currency Indicators: Monetary values are accompanied by currency indicators (e.g., award_currency_first, tender_currency), ensuring that users can accurately interpret financial data.
  • Multiple Currency Representations: Values are provided in different currencies (USD, GBP, EUR) to cater to a diverse range of users and use cases.

11. Status and Metadata Information

  • Status Indicators: tag_status gives the status provided by the publisher at publication, and dps_pred indicates whether we have identified the contract as a framework or dynamic purchasing system.
  • Metadata for Traceability: Metadata fields such as date_created and date_updated provide insights into the data's lifecycle, aiding in version control and auditing.

This structured approach ensures that the JSON output is both user-friendly and comprehensive, facilitating efficient data retrieval and analysis for diverse applications.

Example document

This example document shows how summary records data is structured and published.

{
          "has_attachments": true,
          "cpv_names": [
            "Education and training services",
            "Personnel services except placement and supply services",
            "Specialist training services",
            "Vocational training services",
            "Personal development training services",
            "Business and management consultancy services",
            "Personnel services except placement and supply services",
            "Specialist training services",
            "Vocational training services",
            "Personal development training services",
            "Business and management consultancy services",
            "Education and training services"
          ],
          "tender_url": "https://www.contractsfinder.service.gov.uk/Notice/12ef087c-3ad3-4d72-b2bb-e3d416081402",
          "closing_date": null,
          "awards_usd_value": 0,
          "date_updated": "2024-01-18T02:40:12.144016",
          "buyer_address_country_name": "United Kingdom",
          "tender_eur_value": 0,
          "cpv_aug_names": [
            "Personnel services except placement and supply services",
            "Specialist training services",
            "Vocational training services",
            "Personal development training services",
            "Business and management consultancy services"
          ],
          "cpv_aug_codes": [
            "79630000",
            "80510000",
            "80530000",
            "80570000",
            "79410000"
          ],
          "buyer_name": "DRIVER AND VEHICLE STANDARDS AGENCY",
          "tender_id": "tender_362771/1301350",
          "language": "en",
          "source": "cf_notices",
          "release_tags": "planning",
          "cpv_codes": [
            "80000000",
            "79630000",
            "80510000",
            "80530000",
            "80570000",
            "79410000",
            "79630000",
            "80510000",
            "80530000",
            "80570000",
            "79410000",
            "80000000"
          ],
                    "contracts_eur_value": 0,
          "buyer_address_street_address": "112 Upper Parliament Street",
          "buyer_address_locality": "Nottingham",
          "buyer_address_iso_alpha2": "GB",
          "contracts_gbp_value": 0,
          "contact": "epscategoryteam@dvsa.gov.uk",
          "awards_gbp_value": 0,
          "supplier_names": [],
          "processing_status": "success",
          "supplier_ids": [],
          "ocid": "ocds-0c46vo-0001-12ef087c-3ad3-4d72-b2bb-e3d416081402",
          "buyer_address_region": "England",
          "contracts_usd_value": 0,
          "start_date": null,
          "dps_pred": false,
          "contact_url": null,
          "date_created": "2024-01-16T02:35:38.235781",
          "awards_eur_value": 0,
          "tender_description": """Driver & Vehicle Standards Agency""",
          "award_descriptions": "",
          "tender_gbp_value": 0,
          "tender_usd_value": 0,
          "cpv_aug_data": [
            {
              "cpv_aug_names": "Personnel services except placement and supply services",
              "cpv_aug_codes": "79630000",
              "relevance_score": 16.9238
            },
            {
              "cpv_aug_names": "Specialist training services",
              "cpv_aug_codes": "80510000",
              "relevance_score": 15.2334
            },
            {
              "cpv_aug_names": "Vocational training services",
              "cpv_aug_codes": "80530000",
              "relevance_score": 9.0345
            },
            {
              "cpv_aug_names": "Personal development training services",
              "cpv_aug_codes": "80570000",
              "relevance_score": 8.3424
            },
            {
              "cpv_aug_names": "Business and management consultancy services",
              "cpv_aug_codes": "79410000",
              "relevance_score": 7.7439
            }
          ],
          "release_date": "2024-01-15T12:32:28Z",
          "references_ocids": [],
          "tag_status": "open",
          "tender_title": "Tailored Executive Development",
          "award_titles": ""
}

The following shows an example of a document where lotting features have been identified and collected.

{
     "ocid": "ocds-0c46vo-0001-036588-2025_036588-2025",
     "start_date": "2025-09-04T00:00:00+01:00",
     "date_created": "2025-07-03T01:37:44.838811",
     "tender_description": "Nest is on a path to becoming one of the largest pensions schemes in the UK and our growth trajectory means that the operating model for Nest Invest will need to evolve over the next ten years.\nIn order to support the continued strategic growth and development of the investment function Nest Invest will require ongoing specialist consultancy support for the development of the organisational model and development of the investment approach",
     "award_descriptions": "",
     "tender_gbp_value": 10000000,
     "lots": {
         "lot_descriptions": [
              "1: Strategic investment business, organisational strategy and governance advice with extensive proven experience of international investment best practice with large Financial Conduct Authority (FCA) regulated Occupational Pension Schemes (OPS) with assets under management of £25 billion and above",
              "2: Target Operating Model design and delivery including the transition and implementation of operating models for fund administration and custody service including additional SME operational support as needed to large Financial Conduct Authority (FCA) regulated Occupational Pension Schemes (OPS) (or similar) with assets under management of £25 billion and above. 35",
              "3: Specialist investment consultancy services to large Financial Conduct Authority (FCA) regulated occupational pension schemes (OPS) with assets under management of £25 billion and above"
         ],
         "lot_classifications": [],
         "lot_earliest_start_date": "2025-09-04T00:00:00+01:00",
         "lot_statuses": [
              "active"
         ],
         "lot_identifiers": [],
         "lot_ids": [
              "1",
              "2",
              "3"
         ],
         "lot_currencies": [
              "GBP"
         ],
         "lot_total_value": 10000000.0,
         "lot_count": 3,
         "lot_amounts": [
              3500000.0,
              3500000.0,
              3000000.0
         ],
         "lot_titles": [
              "1: LOT 1 Strategic investment business, organisational strategy and governance advice",
              "2: LOT 2 Target Operating Model design and delivery including the transition and implementation of operating models for fund administration and custody service including additional SME operational support as needed",
              "3: Specialist investment consultancy services to large Financial Conduct Authority (FCA) regulated occupational pension schemes (OPS"
         ],
         "lot_latest_end_date": "2029-09-03T23:59:59+01:00",
         "lot_primary_currency": "GBP",
         "lot_procurement_categories": []
},

Field list

Below we have grouped fields and listed each possible field then and provided a field type and description.

Currencies and conversion

Our currency output adheres to international currency standards by using ISO 4217 codes for currency representation. This ensures that monetary values are clearly identified and standardised across different datasets, facilitating accurate interpretation and conversion. By employing ISO currency codes such as GBP (British Pound), USD (US Dollar), and EUR (Euro), the data maintains consistency and interoperability in financial reporting and analysis.

We use https://exchangeratesapi.io/ for currency conversion, which provides several key benefits, including accurate and up-to-date exchange rates sourced from reliable financial data providers, enhancing the reliability of financial reporting, supporting a wide range of currencies, enabling comprehensive and global financial analysis. Integrating this API into our system ensures that all currency-related data is consistent, precise, and reflects the correct conversion rates at the time of publication.

Values are provided as published by the source. We do not convert between net and gross amounts.

Code Field type Description
award_currency_first String The original currency of an award notice as published in the source data, where the currency is adequately labelled and can be determined by Spend Network. This currency may be any known currency.
award_amount_sum Value The original value of an award as published in the source data, where the value is adequately structured and can be converted to a value field by Spend Network.
awards_usd_value Value The value of award_amount_sum converted from the award_currency_first to USD where the original source is not in USD. Conversion completed on the date of collection, we use https://exchangeratesapi.io/ as our source for currency conversion data.
awards_gbp_value Value The value of award_amount_sum converted from the award_currency_first to GBP where the original source is not in GBP. Conversion completed on the date of collection, we use https://exchangeratesapi.io/ as our source for currency conversion data.
awards_eur_value Value The value of award_amount_sum converted from the award_currency_first to EUR where the original source is not in EUR. Conversion completed on the date of collection, we use https://exchangeratesapi.io/ as our source for currency conversion data.
tender_currency String The original currency of a tender notice as published in the source data, where the currency is adequately labelled and can be determined by Spend Network. This currency may be any known currency. This value is only populated when the source is in OCDS format and the contract notice is appended to a tender notice in a manner compliant with the standard.
tender_amount Value The original value of a tender as published in the source data and where the value is adequately structured and can be converted to a value field by Spend Network. This value is only populated when the source is in OCDS format and the contract notice is appended to a tender notice in a manner compliant with the standard.
tender_usd_value Value The value of tender_amount converted from the tender_currency to USD where the original source is not in USD. Conversion completed on the date of collection, we use https://exchangeratesapi.io/ as our source for currency conversion data. This value is only populated when the source is in OCDS format and the contract notice is appended to a tender notice in a manner compliant with the standard. On award notices, use award_amount_sum and awards_*_value for award values.
tender_gbp_value Value The value of tender_amount converted from the tender_currency to GBP where the original source is not in GBP. Conversion completed on the date of collection, we use https://exchangeratesapi.io/ as our source for currency conversion data. This value is only populated when the source is in OCDS format and the contract notice is appended to a tender notice in a manner compliant with the standard. On award notices, use award_amount_sum and awards_*_value for award values.
tender_eur_value Value The value of tender_amount converted from the tender_currency to EUR where the original source is not in EUR. Conversion completed on the date of collection, we use https://exchangeratesapi.io/ as our source for currency conversion data. This value is only populated when the source is in OCDS format and the contract notice is appended to a tender notice in a manner compliant with the standard. On award notices, use award_amount_sum and awards_*_value for award values.

Entities and Organisations

During our input process we are cleansing fields to provide, reliable consistent values across both buyer names and addresses. In some cases we also match supplier identifiers. The cleansing of buyer names is primarily for the UK, with new links being developed all of the time across other countries. Addresses are cleansed through a proprietary address management algorithm, splitting up codes, identifying postcodes and allocating clean country names, before then deriving a country code.

Name Field type Description
buyer_name String This field contains the name of the buying entity or organisation. It identifies the buyer involved in the tender or contract, facilitating recognition and tracking of the entity.
buyer_address_country_name String The name of the country where the buyer's address is located. Where the source provides an identifiable country name we will amend this entry to provide a consistent reference, e.g. "UK" is converted to "United Kingdom"
buyer_address_locality String The locality or city where the buyer's address is situated. Where we can we seek to extract and separate address features into the correct patterns for greater geographical analysis.
buyer_address_region String The region where the buyer's address is situated. Where we can we seek to extract and separate address features into the correct patterns for greater geographical analysis.
supplier_names String This field lists the names of the suppliers involved in the contract or tender, the data is provided in a list format.
supplier_ids List of strings This field contains unique identifiers for the suppliers, such as registration or company numbers. Where we have reconciled an identifier to a register, it carries a prefix naming that register; identifiers published by the buyer are given as published. Items in this list correlate to the provided supplier name, null items are recorded so that the third id in the list will correspond to the third supplier name in the supplier_name list.
buyer_address_street_address String This field represents the street address of the buyer. Where we can we seek to extract and separate address features into the correct patterns for greater geographical analysis.
buyer_address_iso_alpha2 String This field uses the ISO 3166-1 alpha-2 code to represent the buyer's country. It provides a standardized and internationally recognized format for country identification.

Dates and Times

The following dates and times are used in the contract award documents.

Field Name Field type Description
award_start_date_first Date time The contract start date. It indicates when the contract is scheduled to commence, _first denotes that this is the start date for the first published award.
award_end_date_first Date time The contract end date. It indicates when the contract is scheduled to be completed, _first denotes that this is the end date for the first published award.
release_date Date time The publisher's own record for the date that the document was published. Some sources publish this without a time zone offset; do not assume it is UTC.
date_updated Date time The most recent modification of the record by Open Opportunities, in UTC.
tender_end_date Date time The submission deadline published by the source. Some sources publish this without a time zone offset; do not assume it is UTC. Use this field to decide whether a tender is currently open.
date_created Date time This field indicates the date gathered by Spend Network. It marks when the data was collected and recorded, in UTC. If there is no release date or start date, this date is the best substitute.

Document identifiers

We use the following document identifiers in the output, these are identifiers for the documents, OCIDs can be used as reliable database keys and are unique. By using these identifiers, we ensure that each document can be accurately tracked, referenced, and integrated into various data systems, supporting robust data management and analysis practices.

Field Name field type Description
tender_id String The identifier for the notice, taken from the source. For some sources we derive it from the source's notice number or URL, so it may not match the reference shown on the publisher's site.
ocid String This field is Spend Network's unique identifier, compliant with the Open Contracting Data Standard. It ensures consistent and standardised identification of contracts.
references_ocids Array of objects Other records that our matching process found similar to this one, each given as {ocid: similarity score} with a score between 0 and 1. A listed record may be a different procurement by the same buyer. Treat these as hints to investigate, not as confirmed duplicates or procurement links.

Status and Metadata

Status and metadata tags provides information on the origin of the data, categorization of document types, the status of contracts, and classification of contract types. Each entry ensures clarity and consistency, facilitating accurate data interpretation and analysis.

Field Name Data Type Description
source String This field contains the name of the source code used to harvest the data. It indicates the origin of the data collection process.
release_tags String The document type. See Release Tags below for the full list of values. A small number of sources publish amendments as stand-alone documents; these arrive as separate records with an amendment release tag and are not linked to the original notice.
tag_status String The status provided by the publisher when the notice was published. It is not updated as the notice progresses and must not be used to show whether a notice is currently open or closed. Use tender_end_date for that.
dps_pred Boolean This field denotes whether Spend Network has identified that this contract is a framework or dynamic purchasing system (DPS) contract. It helps in classifying the type of contract.
language String ISO 639 language classification, automatically derived from a Google large language model.

Descriptions and Titles

The following table provides a detailed description of the narrative fields within the JSON output related to tenders and awards.

→ award titles → comes in as a list, converted to a string (never an array)

→ Only for OCDS linked titles and awards

Field Name Data Type Description
tender_title String This field contains the title of the tender. It provides a brief and specific name for the tender, summarising its main purpose. This value is only populated when the source is in OCDS format and the contract notice is appended to a tender notice in a manner compliant with the standard.
content String This field combines both the tender title and description, enabling more efficient in-memory text searching.
tender_description String This field provides a detailed description of the tender. It includes the published information about the tender's requirements and objectives. This value is only populated when the source is in OCDS format and the contract notice is appended to a tender notice in a manner compliant with the standard.
award_descriptions String This field contains descriptions of the awards associated with the tender. It provides published information about the awards granted. In the event that multiple awards are added as separate releases to a single tender, the awards descriptions will be concatenated in this field
award_titles String This field includes the titles of the awards. It gives a concise and specific name for each award associated with the tender. In the event that multiple awards are added as separate releases to a single tender, the awards titles will be concatenated in this field.

Contact Information

The following table provides a detailed description of specific fields within the JSON output related to contact information. Each field is accompanied by its data type and a brief description, facilitating a better understanding of the contact details provided and aiding in efficient data interpretation and analysis.

Field Name Data Type Description
contact String This field contains the email address of the contact person or entity. It provides a direct communication channel for inquiries or further information.
contact_url String This field includes the URL for contact information. It offers an online link for additional contact details or communication methods.

Classification Codes

The following table provides a detailed description of specific fields within the JSON output related to procurement classification. Each field is accompanied by its data type and a brief description, facilitating a better understanding of the procurement categories and aiding in efficient data interpretation and analysis. CPV stands for Common Procurement Vocabulary, the EU procurement classification system, while "aug" stands for augmented, indicating additional codes added by Spend Network.

Field Name Data Type Description
cpv_names Array This field contains an array of names from the Common Procurement Vocabulary (CPV) that were provided by the original publisher.
cpv_aug_names Array This field includes an array of augmented CPV names added by Spend Network. It offers additional classification names that enhance the standard CPV categorisation.
cpv_aug_codes Array This field contains an array of augmented CPV codes added by Spend Network. It provides additional classification codes that complement the standard CPV codes.
cpv_codes Array This field includes an array of CPV codes from the Common Procurement Vocabulary that were provided by the original publisher.
cpv_aug_data Array of objects One entry per augmented code, giving cpv_aug_codes, cpv_aug_names and relevance_score (0 to 100).

Augmented codes are assigned at the four-digit group level (e.g. 34120000).

URLs

The following table provides a detailed description of a specific field within the JSON output related to the URL of the published tender.

Field Name Data Type Description
tender_url String This field contains the original source URL of the published tender. It provides a direct link to the tender's publication, enabling access to the full tender details and documentation.

Lots

The following table provides a detailed description of a specific field within the JSON output related to lots in a published document.

Field name Data Type Description
lots.lot_count Integer The number of lots into which the tender or award is divided. Used to identify whether the procurement is split and how many components it includes.
lots.lot_ids Array of Strings A list of identifiers for each individual lot. These identifiers are typically numeric strings (e.g., "1", "2").
lots.lot_titles Array of Strings Titles of each lot. These provide a concise description of the lot's scope or purpose. Titles may include a prefix indicating lot number.
lots.lot_descriptions Array of Strings Descriptive narrative for each lot. These typically include eligibility criteria, scope, or technical requirements.
lots.lot_amounts Array of Numbers Monetary values for each lot, expressed in the primary currency. These represent the estimated or awarded value for each lot.
lots.lot_total_value Number The total value of all lots combined. Used for summarizing the overall contract value when split across multiple components.
lots.lot_primary_currency String The ISO 4217 currency code used for all monetary amounts within the lot object (e.g., GBP).
lots.lot_currencies Array of Strings List of currencies applicable to the lots. Useful in cross-border or multi-currency procurement.
lots.lot_earliest_start_date DateTime The earliest scheduled start date for any of the lots.
lots.lot_latest_end_date DateTime The latest scheduled end date for any of the lots.
lots.lot_statuses Array of Strings Statuses of individual lots (e.g., "active", "cancelled"). Multiple statuses may exist across lots in the same contract.
lots.lot_classifications Array A placeholder for CPV or other classification codes relevant to the lots. Currently not populated.
lots.lot_procurement_categories Array Reserved for categorisation of lots by procurement category (e.g., goods, services, works). Currently not populated.

Attachments

The following table provides a detailed description of a specific field within the JSON output related to the availability of attachments for a given document.

Field Name Data Type Description
has_attachments Boolean A field that shows whether a document has attachments associated with it.
attachments Array This field contains a list of urls for attachments that have been found for the given search. Each entry has a field for title and url. This field is only present when the user has added attachment__show to their API request.
attachments.title String The title of an attachment gathered from a specific page. This field is only present when the user has added attachment__show to their API request.
attachments.url URL The original URL of the attachment. This field is only present when the user has added attachment__show to their API request.

API requests

Accessing the Spend Network API Endpoint

The summary records endpoint uses a POST request with a JSON body.

API Endpoint URL

POST https://api.spendnetwork.cloud/api/v3/notices_summary/read_summary_records

Request Body Parameters

All parameters are optional and passed in the JSON request body:

Name Type Description
search_term__is string Search term to include (maxLength: 2000). Supports multi-word phrases, boolean operators (AND, OR, NOT, uppercase), and quoted phrase matching in loose mode.
search_term__exclude string Search term to exclude. Recommended maximum 500 characters.
buyer_name__is string Buyer name to include. Recommended maximum 500 characters; very long values may exceed internal query limits.
supplier_name__is string Supplier name to include. Recommended maximum 500 characters; very long values may exceed internal query limits.
buyer_address_country_name__is string Country name of the buyer to include.
buyer_address_country_name__exclude string Country name of the buyer to exclude.
buyer_address_country_code__is array[string] Country codes of the buyer to include.
buyer_address_country_code__exclude array[string] Country codes of the buyer to exclude.
ocid__is string Open Contracting ID to include.
language__is array[string] Languages to include.
language__exclude array[string] Languages to exclude.
tender_deadline__gte string($date-time) Tender deadline greater than or equal to.
tender_deadline__lte string($date-time) Tender deadline less than or equal to.
contract_start_date__gte string($date-time) Contract start date greater than or equal to.
contract_start_date__lte string($date-time) Contract start date less than or equal to.
contract_start_date__is string($date-time) Contract start date exactly.
contract_end_date__gte string($date-time) Contract end date greater than or equal to.
contract_end_date__lte string($date-time) Contract end date less than or equal to.
contract_end_date__is string($date-time) Contract end date exactly.
release_date__gte string($date-time) Release date greater than or equal to.
release_date__gt string($date-time) Release date greater than.
release_date__lte string($date-time) Release date less than or equal to.
release_date__lt string($date-time) Release date less than.
release_tags__is array[string] Release tags to include - defined as an array with one or more of the tags published by publishers using OCDS (see below).
tag_status__is string Status provided by the publisher at publication. Do not use to find currently open notices; filter on tender_deadline__gte instead.
cpv__is array[string] CPV codes to include.
dps_pred__is boolean Whether the contract is a dynamic purchasing system contract.
predicted_cpv_values boolean Include predicted CPV values.
cpv_aug_threshold float Filter CPV augmented values by relevance score threshold (0-100).
sort_by string Sort field: release_date, date_created, date_updated, tender_end_date. Default: release_date. Does not apply when search_term__is is set: results are then ordered by relevance.
date_direction string Date sort direction (asc or desc). Default: desc.
offset integer Pagination offset (min: 0, max: 9900).
limit integer Number of records to return (min: 0, max: 10,000). There is no default.
prefix_search boolean Enable prefix search for CPV codes only , has no effect on search_term__is. When true, CPV codes in cpv__is are matched as prefixes (e.g. 45 matches all 45xxxxxx codes).
value__gte integer Minimum value (min: 0). Applies to the published tender or award value.
value__gt integer Greater than value (min: 0).
value__lte integer Less than or equal to value (min: 0).
value__lt integer Less than value (min: 0).
currency__is string Currency to query for (maxLength: 3, e.g., USD, GBP, EUR).
dedupe__is boolean true removes duplicate records we have identified.
attachment__show boolean Call to include original URLs and file names from attachments.
attachment__is boolean Show only results with attachments.
search_language__is array[string] Language codes that set the analyser used for stop words and stemming (e.g. ["en"], ["fr", "de"]). A single language uses that language's analyser. Where several languages are given and English is among them, the English analyser is used; otherwise the standard analyser is used. Only applies in strict and medium modes.
search_mode string Controls search strictness. "loose" (default): OR operator, 50% minimum match, fuzzy matching, supports Lucene syntax including quoted phrases and wildcards. Use wildcards (e.g. autobus*) to match inflected forms. "medium": all words required (AND), 75% minimum match, proximity boosting, fuzziness. "strict": exact phrase match, no fuzziness.

Release Tags

Release tag items can be one or more of the following and expressed in an array. A small number of sources publish amendments as stand-alone documents; these arrive as separate records with an amendment release tag.

tender
award
planning
award contract
contract award
tenderUpdate
awardUpdate
tenderAmendment
planningUpdate
awardUpdate contractUpdate
contractUpdate awardUpdate
tender planning
tenderCancellation
planning tender
contractAmendment
contractTermination
planning award
planningUpdate award
award planning
award planningUpdate

Example Code

import requests

URL = "https://api.spendnetwork.cloud/api/v3/notices_summary/read_summary_records"

query = {
    "release_tags__is": ["tender"],
    "date_direction": "desc",
    "offset": 0,
    "limit": 50,
}

def fetch_summary_records(access_token):
    try:
        response = requests.post(
            URL,
            json=query,
            headers={
                "Accept": "application/json",
                "Content-Type": "application/json",
                "Authorization": f"Bearer {access_token}",
            },
        )

        response.raise_for_status()
        return response.json()
    except requests.RequestException as error:
        print("Fetch error:", error)
        return None

records = fetch_summary_records("YOUR_ACCESS_TOKEN")
print(records)

Authentication

To access the API users need to generate a bearer token. This is generated by making a call to the access-token endpoint /api/v3/login/access-token which uses an OAuth2 compatible login, and returns an access token for future requests. Supports both JSON and form data formats. The payload returns a token and the expiration date as follows. To refresh the token just call the access-token endpoint with your credentials.

curl -s -X POST "https://api.spendnetwork.cloud/api/v3/login/access-token" \
  -H "Content-Type: application/json" \
  -d '{"username":"your_email@example.com","password":"your_password"}'

Response:

{
  "access_token": "eyJhbGciOiJIUzI.........",
  "token_type": "bearer",
  "expiration_date": "2024-12-31T23:59:59"
}

Replace "Bearer YOUR_ACCESS_TOKEN" with your actual API access token.

For detailed API documentation and additional options, visit the Spend Network API Swagger page.

Error Handling

When interacting with the API, it is important to handle potential errors gracefully. This includes checking for HTTP errors and handling exceptions appropriately.

def fetch_summary_records(access_token):
    try:
        response = requests.post(
            "https://api.spendnetwork.cloud/api/v3/notices_summary/read_summary_records",
            json=query,
            headers={
                "Accept": "application/json",
                "Content-Type": "application/json",
                "Authorization": f"Bearer {access_token}",
            },
        )

        response.raise_for_status()
        return response.json()

    except requests.HTTPError as http_err:
        print(f"HTTP error occurred: {http_err}")
    except requests.RequestException as error:
        print("Fetch error:", error)
    except Exception as err:
        print(f"An error occurred: {err}")
    return None

records = fetch_summary_records("YOUR_ACCESS_TOKEN")
print(records)

Example Request Bodies

Customise the request body for specific use cases to retrieve the desired data.

query = {
    "date_direction": "asc",
    "offset": 0,
    "limit": 10,
    "release_tags__is": ["award"],
    "buyer_name__is": "MINISTRY OF DEFENCE",
}

Rate Limiting

New notices are published twice a day, typically at 6am and 11am GMT. Collect once after each publishing run; polling between runs returns no new data. Implement retry with exponential backoff rather than retrying immediately.

Pagination

To handle large datasets, use the offset and limit parameters to paginate results. Note that there is a 10,000 record limit on what can be returned from any single query.

query = {
    "offset": 0,
    "limit": 100  # Adjust as necessary, up to 10,000
}

while True:
    result = fetch_summary_records("YOUR_ACCESS_TOKEN")
    if not result or len(result.get("results", [])) < query["limit"]:
        break
    query["offset"] += query["limit"]

How to filter notices by CPV

This guide explains how to use:

  • cpv__is
  • prefix_search

Filtering by CPV (**cpv__is**)

Send a list of CPV codes in the JSON request body:

{
  "cpv__is": ["48000000", "72000000", "85000000"]
}

Prefix CPV matching (**prefix_search**)

When should you use prefix search?

Use prefix_search=true when you want to match a family of CPV codes.

Example:

  • If you send 48000000 with prefix_search=true, the API treats it like "anything starting with 48".
  • That means codes like 48100000, 48200000, etc. can match.

How to enable it

{
  "cpv__is": ["48000000", "72000000"],
  "prefix_search": true
}

What happens with trailing zeros

With prefix_search=true, the system removes trailing zeros to create the prefix:

  • 48000000 becomes prefix 48
  • 72000000 becomes prefix 72

Sample responses

Here is an example of a typical response from the API:

{
    "offset": 0,
    "limit": 10,
    "result_count": 1234,
    "results": [
        {
            "tender_id": "tender_278767/1024151",
            "buyer_name": "MINISTRY OF DEFENCE",
            "tender_title": "The provision of End Point Assessment for Digital Apprenticeship Standards",
            "release_date": "2021-12-17T08:27:49Z",
            ...
        }
    ]
}

result_count is counted before deduplication, so it can exceed the number of records returned when dedupe__is is true.

Best Practices

  • Optimize Queries: Use specific and relevant query parameters to limit the amount of data returned.
  • Caching: Implement caching strategies to reduce the number of API calls and improve performance.
  • Error Handling: Ensure robust error handling to manage API errors gracefully.
  • Rate Limits: Be mindful of API rate limits and implement retry mechanisms where necessary.
  • Pagination: Use pagination to handle large datasets efficiently.

API Limitations

  • Record Limit: There is a 10,000 record limit on what can be returned from any query. Use pagination to retrieve additional records.
  • Publishing Frequency: New notices are published twice a day, so ensure your application accounts for this cycle.

Contact Information

For further assistance or questions about the API, please contact our support team at contact@openopps.com.

Further code examples

Example Javascript code

The following JavaScript code demonstrates how to access the Spend Network summary records API. This script constructs a query body and sends an HTTP POST request to the endpoint. Replace TOKEN HERE with your actual API access token.

const URL = "https://api.spendnetwork.cloud/api/v3/notices_summary/read_summary_records";

const query = {
    release_tags__is: ["tender"],
    date_direction: "desc",
    offset: 0,
    limit: 50,
};

export const fetchSummaryRecords = async () => {
    try {
        const response = await fetch(URL, {
            method: "POST",
            headers: {
                Accept: "application/json",
                "Content-Type": "application/json",
                Authorization: `Bearer TOKEN HERE`, // please add your sn-api access token
            },
            body: JSON.stringify(query),
        });

        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }

        const body = await response.json();
        return body;
    } catch (error) {
        console.error("Fetch error:", error);
        return null;
    }
};

Example Python code

The following Python code demonstrates how to access the Spend Network summary records API. This script constructs a query body and sends an HTTP POST request to the endpoint.

Replace "Bearer TOKEN HERE" with your actual API access token.

import requests

URL = "https://api.spendnetwork.cloud/api/v3/notices_summary/read_summary_records"

query = {
    "release_tags__is": ["tender"],
    "date_direction": "desc",
    "offset": 0,
    "limit": 50,
}

def fetch_summary_records(access_token):
    try:
        response = requests.post(
            URL,
            json=query,
            headers={
                "Accept": "application/json",
                "Content-Type": "application/json",
                "Authorization": f"Bearer {access_token}",
            },
        )

        response.raise_for_status()
        return response.json()
    except requests.RequestException as error:
        print("Fetch error:", error)
        return None

records = fetch_summary_records("TOKEN HERE")
print(records)

Document Attachments

Spend Network's summary API now supports both sourcing and downloading attachments (e.g. PDFs, DOCs) related to individual tender or contract documents. This feature allows users to programmatically access attachments, either via the original source information or through a direct download via Spend Network's servers.

Filtering For Attachments

Our API contains a boolean that shows when a document has attachments associated with it. Users can use the attachment__is feature in their query to return only documents with attachments, or alternatively only those without attachments.

Example Query Parameters

{
    "attachment__is": true,
    "date_direction": "asc",
    "offset": 0,
    "limit": 10,
    "release_tags__is": ["award"],
    "buyer_name__is": "MINISTRY OF DEFENCE"
}

Show Attachment Sources

In order to be able to provide a source URL for a given attachment we have an additional feature that can be called which adds the sourcing data to the document payload.

To retrieve document metadata (i.e. the titles and source URLs) for attachments associated with published tenders or contracts, API users can include the attachment__show parameter in your request for a specific document:

Parameter Type Description
attachment__show boolean (optional, default: false) When set to true, the response will include an attachments field with a list of attachment metadata.

Example Query Parameters

Users should use the attachment__show parameter on a document by document basis to retain response time performance. Queries for multiple files will NOT be fast enough for production environments.

{
  "attachment__show": true,
  "ocid__is": "ocds-0c46vo-0001-12ef087c-3ad3-4d72-b2bb-e3d416081402",
}

Example Response Snippet

...
"attachments": [
  {
    "title": "Entwurfsplanung Heizung KG.pdf",
    "url": "https://www.vergabe-westfalen.de/.../Entwurfsplanung+Heizung+KG.pdf"
  },
  {
    "title": "LV Heizflächen Altbau.d83",
    "url": "https://www.vergabe-westfalen.de/.../LV+Heizfl%C3%A4chen+Altbau.d83"
  }
]
...

Downloading Attachments via Spend Network API

To simplify access to attachment files (bypassing source website restrictions), two dedicated endpoints are provided:

1. List Available Attachment Files

This allows users to list attachment files by title and url for a specific document.

Endpoint:

POST https://api.spendnetwork.cloud/api/v3/attachments/list

Authentication Required: Yes (Bearer token)

Parameter Type Description
source string Internal source identifier (e.g. td_vergabe_westfalen_de)
tender_id string Unique tender ID (from the summary API)

Example

The following request allows the user to return a list of attachments associated with a specific document.

curl -X POST \
  'https://api.spendnetwork.cloud/api/v3/attachments/list' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
        "source": "td_vergabe_westfalen_de",
        "tender_id": "41878101"
      }'

Response

We use underscores (_) in filename values instead of period characters (.) to ensure compatibility with URL paths and to avoid issues with file extension parsing or routing logic in some systems.

[
  {
    "title": "SubmissionForm.docx",
    "filename": "submissionform_docx"
  }
]

Note: This filename value is required for the download endpoint.

2. Download Specific Attachment File

Endpoint Format:

GET /api/v3/attachments/download/{source}/{tender_id}/{filename}

Note: Use the tender_id field not the ocid identifier.

Example

curl -X GET \
  'https://api.spendnetwork.cloud/api/v3/attachments/download/td_vergabe_westfalen_de/41878101/submissionform_docx' \
  -H 'Accept: application/json'

Behavior:

Returns the file as a direct download. In the event that the incorrect link has been used the API will return a Attachment file not found error.

How It Fits Together

  1. If has_attachments is true for a document, then you will get a response from the /attachments/list endpoint.
  2. Get the source and tender_id from the returned JSON, and check for available attachments using the /attachments/list end point.
  3. Use /attachments/list to retrieve a full list of filenames for that record.
  4. Compile a query using the source , tender_id and filename from memory and send a request to the /attachments/download/... end point to fetch a specific file by filename.

Best Practices

  • Use /attachments/list to get valid filenames for a specific document before calling /attachments/download.
  • Ensure that the source and tender_id match what is returned from the summary API.
  • Always authenticate using your API token on both endpoints.
  • Collect attachments on the basis of user demand, rather than in advance in aggregate.