Skip to main content
Technology

From Data to Intelligence: What the Tenders-SA API Actually Gives You

Raw government procurement feeds are fragmented and incomplete. The Tenders-SA Developer API layers AI enrichment, consistent schemas, multi-language SDKs, and award analytics over these feeds. Here is what that means for your platform.

What You Actually Get When You Call the API

The Tenders-SA Developer API sits between raw government procurement feeds and your application. It does not just proxy data — it transforms it. Every endpoint returns enriched, structured, and documented data that is ready to display, analyse, or store. This article is a transparent look at what each endpoint actually gives you, what the enrichment pipeline does, and how the SDKs make it accessible.

The API serves from a dedicated infrastructure at https://api.tenders-sa.org/v1

. It has its own database, synced from the main platform, so it remains fast and available independently of the Tenders-SA web application.

The Data Pipeline: From Government Feed to API Response

Understanding what you are getting means understanding where it comes from. Here is the pipeline that every tender passes through before it reaches an API response:

  1. Ingestion — The platform fetches OCDS data from government feeds: National Treasury eTenders, Eskom, Transnet, SANRAL, provincial portals, and municipal systems. Raw OCDS JSON arrives with inconsistent schemas, missing fields, and varying naming conventions.
  2. Normalisation — Province names are standardised (e.g. "GP" → "Gauteng"), status values are mapped to a consistent set (OPEN, CLOSED, AWARDED, CANCELLED), and procurement categories are classified against a unified taxonomy.
  3. AI Enrichment — Every tender is processed through AI pipelines. This generates an executive summary, extracts key requirements and evaluation criteria, estimates the tender value range based on document content analysis, and classifies the tender into its primary and secondary categories.
  4. Document Processing — Associated documents are fetched and stored in Cloudflare R2 with metadata tracked in D1. Document URLs are repaired and made accessible through the document endpoint.
  5. Synchronisation — The API database is synced from the main platform, making enriched data available through REST endpoints.

The result is a dataset that is significantly more useful than the raw OCDS source. A tender that arrives from a government feed with a title, an organisation name, and a cryptic status code comes out the other end with a human-readable summary, an estimated value range, a classified category, extracted requirements, and linked documents.

The Enrichment Layer: What AI Actually Adds

The AI enrichment layer is the core differentiator of the Tenders-SA API. Here is what it produces for every tender:

FieldSourceWhat It Contains
aiSummaryAI-generated2-3 paragraph executive summary of the tender, extracted from document content and notice text
aiRequirementsAI-extractedKey submission requirements, evaluation criteria, and mandatory documentation
estimatedValueMin / estimatedValueMaxAI-estimatedEstimated value range based on historical award data for similar tenders and document analysis
categoryAI-classifiedPrimary procurement category matched against the unified category taxonomy
subcategoryAI-classifiedSecondary classification for finer-grained filtering
statusNormalisedMapped to OPEN, CLOSED, AWARDED, CANCELLED — consistent across all sources
provinceNormalisedGeography resolved to standardised province name
issueDate / closingDateParsedNormalised ISO 8601 date strings

This enrichment does not depend on the source feed quality. Even a sparse OCDS release with only a title and organisation name will receive a summary, value estimate, and category assignment through the AI pipeline. That means you get usable data even for tenders where the government feed was incomplete.

Every Endpoint and What It Returns

The API exposes five resource groups. Here is a detailed walkthrough of each.

Tenders — The Core Dataset

The tenders resource is the primary interface for all procurement opportunities in the system.

EndpointWhat It Returns
GET /v1/tendersPaginated list of tenders with summary fields. Supports 10+ filter parameters: status, province, category, value range, closing date range, sort order, and sparse field selection.
GET /v1/tenders/{id}Full tender object with all enriched fields: summary, requirements, value estimate, category, timeline dates, linked organisation profile, and related awards.
GET /v1/tenders/searchSemantic search results across all active tenders. Uses AI-powered matching rather than keyword matching, so a search for 'road construction' will surface tenders about 'national road maintenance' and 'bridge repairs'.
GET /v1/tenders/{id}/documentsList of associated documents with download URLs. Documents that have been cached in R2 return a reliable public URL. The document metadata includes file name, type, and size.
GET /v1/tenders/{id}/awardsAward history for a specific tender, including winning supplier, contract value, BEE level, and enterprise type.
GET /v1/tenders/{id}/timelineFull procurement timeline: publication, briefing session, deadline, award date, contract start and end.
GET /v1/tenders/{id}/analysisAI-generated analysis with structured sections: summary, requirements, compliance checklist, and evaluation criteria.
GET /v1/tenders/{id}/value-estimateEstimated value range with confidence indicators and methodology notes.

Awards — Contract Intelligence

The awards resource surfaces who won what, for how much, and under what conditions.

EndpointWhat It Returns
GET /v1/awardsPaginated list of awarded contracts with filterable fields: supplier name, province, category, value range, BEE level, enterprise type, and award date range.
GET /v1/awards/{id}Full award detail including supplier profile, contract value, BEE level, enterprise type (SMME, QSE, etc.), issuing organisation, and applicable legislation.
GET /v1/awards/analyticsAggregated award analytics grouped by province, category, enterprise type, or BEE level. Returns totals, counts, and percentage distributions for the selected dimension.

The analytics endpoint is particularly useful for market research and reporting. For example, you can see the distribution of award value by BEE level across all tenders in the Western Cape, or compare contract volumes between construction and IT over a specific period.

Companies and Organisations — Entity Profiles

EndpointWhat It Returns
GET /v1/companies/{name}Company intelligence profile: award history, total contract value, enterprise type, BEE level, and compliance indicators aggregated from public procurement records.
GET /v1/companies/searchCompany search by name, BEE level, province, or industry sector.
GET /v1/organizations/{id}Procurement body profile: name, contact details, and sourcing category focus.
GET /v1/organizations/{id}/tendersAll tenders issued by a specific procurement body.

Meta — Platform Status and Reference Data

EndpointWhat It Returns
GET /v1/meta/statusAPI health check with data freshness timestamp — confirms the API is operational and how recently data was synchronised.
GET /v1/meta/provincesAll nine provinces with active tender counts. Useful for powering dropdown filters and geographic selectors.
GET /v1/meta/categoriesAll procurement categories with tender counts. Useful for filter UIs and category browsing.
GET /v1/meta/usageYour API usage statistics across all registered keys: requests today, this month, remaining quota, and reset times.

Working with the API in Practice

All API responses follow a consistent envelope format. A successful response looks like this:

1{
2  "success": true,
3  "data": { ... },
4  "meta": {
5    "requestId": "req_uuid",
6    "timestamp": "2026-05-28T10:00:00Z",
7    "apiVersion": "v1",
8    "page": 1,
9    "pageSize": 20,
10    "totalCount": 142,
11    "totalPages": 8,
12    "hasNext": true,
13    "hasPrev": false,
14    "rateLimit": {
15      "limit": 500,
16// ... (truncated)
JSON

Key design decisions in the response format:

  • The success boolean lets you check the outcome without parsing status codes.
  • Every response includes a requestId — useful for debugging and support.
  • Pagination metadata is always present on list endpoints, even for single-page results.
  • Rate limit information is in both HTTP headers and the body meta.rateLimit so you never need to parse headers if you prefer the body.
  • The fields query parameter lets you request subsets of fields — GET /v1/tenders?fields=tenderId,title,status — reducing payload size significantly on list endpoints.

SDK Design: What the Client Handles for You

The three official SDKs share a consistent design philosophy. Each one hides HTTP mechanics behind a resource-oriented interface:

1client.tenders.list(filters)     // → ListResponse<Tender>
2client.tenders.get(id)           // → ApiResponse<Tender>
3client.tenders.search(query)     // → ListResponse<Tender>
4client.tenders.documents(id)     // → ListResponse<Document>
5client.tenders.awards(id)        // → ListResponse<Award>
6client.tenders.analysis(id)      // → ApiResponse<Analysis>
7client.tenders.valueEstimate(id) // → ApiResponse<ValueEstimate>
8client.tenders.timeline(id)      // → ApiResponse<Timeline>
9client.tenders.listPages(filters) // → AsyncIterator<Tender[]>
TEXT

What the SDK handles transparently:

  • Authentication — You pass the API key once in the constructor. The SDK attaches the Authorization header to every request.
  • Pagination — List endpoints return paginated results. The listPages() method (JavaScript) and paginated() method (Python) provide async iterators that automatically fetch subsequent pages.
  • Error mapping — Every HTTP status maps to a typed error class. A 401 becomes AuthError, a 404 becomes NotFoundError, a 429 becomes RateLimitError. Each error exposes status, code, message, and requestId.
  • Rate limit tracking — The client stores the most recent rate limit snapshot, accessible via client.lastRateLimit.
  • Retry with backoff — Transient failures (5xx, network errors) are retried with exponential backoff. Configurable via the retry option in the constructor.
  • Key conversion (Python SDK only) — The Python SDK automatically converts camelCase API fields to snake_case Python attributes.

Error Handling: The Complete Picture

Every API error returns a structured response:

1{
2  "success": false,
3  "error": "Not found",
4  "code": "NOT_FOUND",
5  "message": "The requested resource was not found",
6  "requestId": "req_xxx",
7  "docs": "https://tenders-sa.org/developers/docs/errors#NOT_FOUND",
8  "timestamp": "2026-05-28T10:00:00Z"
9}
JSON

Each error response includes a docs URL pointing to documentation for that specific error code. The SDKs throw typed exceptions that expose all of these fields so you can handle errors programmatically:

1try {
2  const result = await client.tenders.get('nonexistent')
3} catch (err) {
4  if (err instanceof AuthError) {
5    console.error('Invalid API key. Get one at https://tenders-sa.org/developers/api-keys')
6  } else if (err instanceof NotFoundError) {
7    console.error('Tender not found')
8  } else if (err instanceof RateLimitError) {
9    console.error(`Rate limited: ${err.used}/${err.limit}`)
10  } else if (err instanceof TendersaError) {
11    console.error(`API error [${err.code}]: ${err.message} (request: ${err.requestId})`)
12  }
13}
TYPESCRIPT

What You Cannot Get from the Public Widget API (But Can Get from the Developer API)

The public widget endpoints at /api/widgets/* are open-access and do not require authentication. They are designed for the four embeddable widgets and expose aggregated or limited views of the data. The Developer API provides everything the widget API does — plus the following:

  • Full tender detail with AI analysis, requirements, value estimates, and document lists.
  • Award records with supplier names, BEE levels, contract values, and enterprise types.
  • Company intelligence profiles with aggregated award history.
  • Organisation (procurement body) profiles and their tender history.
  • Award analytics with grouping by province, category, BEE level, or enterprise type.
  • Semantic search across all active tenders.
  • Sparse field support for payload size optimisation.

Source Code and Documentation

Everything described in this article is available today. Here are the key links:

ResourceLink
Developer Portal (API keys)tenders-sa.org/developers/api-keys
API Documentationtenders-sa.org/publishers/developers
JavaScript/TypeScript SDKgithub.com/Tenders-SA/js
Python SDKgithub.com/Tenders-SA/python
CLIgithub.com/Tenders-SA/cli
Widget: Heatmapgithub.com/Tenders-SA/widget-heatmap
Widget: Sector Trendsgithub.com/Tenders-SA/widget-sector-trends
Widget: Top Companiesgithub.com/Tenders-SA/widget-top-companies
Widget: Winners Feedgithub.com/Tenders-SA/widget-winners-feed
Publishers Portaltenders-sa.org/publishers
Platform Hometenders-sa.org

All SDKs and widgets are open source under the MIT license. Issues and pull requests are welcome on any of the GitHub repositories.

Tags

APIDeveloper ToolsSDKOpen SourceProcurement DataGovernment DataAI EnrichmentREST API
AI-Powered Matching
Never Miss a Perfect Tender Again
Our AI analyzes thousands of tenders and finds the ones YOUR company can actually win
AI Match Scoring for every tender
Instant alerts for 85%+ matches
B-BBEE level optimization
Document readiness checks

Share this article

From Data to Intelligence: What the Tenders-SA API Actually Gives You

Raw government procurement feeds are fragmented and incomplete. The Tenders-SA Developer API layers AI enrichment, consistent schemas, multi-language SDKs, and award analytics over these feeds. Here is what that means for your platform.

https://www.tenders-sa.org/blog/tenders-api-what-it-gives-you