The Tenders-SA Developer API: Programmatic Access to South African Procurement Data
A technical guide to the Tenders-SA Developer API — authentication, endpoints, pagination, rate limiting, error handling, and sparse field support. For developers building on top of SA public procurement data.
Programmatic Access to South African Procurement Data
Tenders-SA.org aggregates tenders from national, provincial, and municipal government departments, SOEs (Eskom, Transnet, SANRAL), and public entities across South Africa. The data is sourced directly from official OCDS (Open Contracting Data Standard) feeds and then enriched through AI pipelines for summarisation, requirement extraction, value estimation, and classification.
The Tenders-SA Developer API exposes this enriched procurement data through a set of RESTful endpoints. It runs on a dedicated infrastructure layer with its own database — synced from the main platform — so the API remains fast and available independently of the web application. This guide covers the API architecture, authentication, available endpoints, and usage patterns.
Before diving into the technical details, it's worth being clear about who this API is for and what problems it typically solves. Developers reach for the Tenders-SA API when they need procurement data inside a product or process that isn't the Tenders-SA website itself: an internal bid-tracking tool for a mid-sized construction firm, a research dashboard analysing award patterns across provinces, a plugin that surfaces relevant tenders inside an existing business tool, or an automated script that checks for new opportunities in a specific category every morning. In each case, the alternative to using the API is manually re-checking the website or, worse, re-scraping government portals directly — something the API's own enrichment pipeline has already done the hard work of normalising and structuring.
API Base URL and Authentication
All API requests are made to the following base URL:
1https://api.tenders-sa.org/v1TEXT
Authentication is handled via Bearer tokens passed in the Authorization header. API keys use the format tsa_prod_ followed by a unique generated string:
1Authorization: Bearer tsa_prod_your_api_keyTEXT
API keys are generated through the Developer Portal. Access requires a Professional or Enterprise subscription with the following rate limits:
| Plan | Max API Keys | Daily Limit | Monthly Limit |
|---|---|---|---|
| Professional | 3 | 500 | 15,000 |
| Enterprise | 25 | 10,000 | 300,000 |
Treat your API key with the same care you would a password. Because keys are tied to your subscription's rate limits and permissions, a leaked key in a public repository or client-side script could let someone else consume your daily or monthly quota. Store keys as environment variables in your deployment environment rather than hard-coding them into source files, and rotate a key immediately through the Developer Portal if you suspect it has been exposed.
Response Format
Every API response follows a consistent envelope structure. A successful response contains a success boolean, a data payload, and a meta object with pagination and rate limit information:
1{ 2 "success": true, 3 "data": { ... }, 4 "meta": { 5 "requestId": "req_uuid", 6 "timestamp": "2026-01-01T00: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
Error responses follow a similar pattern with an error string, a machine-readable code, a human-readable message, and a docs URL pointing to the relevant error documentation:
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-01-01T00:00:00Z" 9}JSON
Available Endpoints
The API is organised into five resource groups. Here is every available endpoint with its purpose:
Tenders
| Endpoint | Method | Description |
|---|---|---|
| /v1/tenders | GET | List tenders with filters (status, province, category, value range, closing date) |
| /v1/tenders/{id} | GET | Get a single tender with all enriched fields |
| /v1/tenders/search | GET | AI-powered semantic search across all active tenders |
| /v1/tenders/{id}/documents | GET | List associated tender documents with download URLs |
| /v1/tenders/{id}/awards | GET | Get award history for a specific tender |
| /v1/tenders/{id}/timeline | GET | Full procurement timeline from publication to award |
| /v1/tenders/{id}/analysis | GET | AI-generated analysis including summary, requirements, and scoring |
| /v1/tenders/{id}/value-estimate | GET | Estimated value range based on document content analysis |
Awards
| Endpoint | Method | Description |
|---|---|---|
| /v1/awards | GET | List awards with filters (supplier, province, category, value range, date range) |
| /v1/awards/{id} | GET | Get a single award with full supplier and contract details |
| /v1/awards/analytics | GET | Aggregated award analytics grouped by province, category, enterprise type, or BEE level |
Companies
| Endpoint | Method | Description |
|---|---|---|
| /v1/companies/{name} | GET | Company intelligence profile with award history, contract values, and compliance data |
| /v1/companies/search | GET | Search companies by name, BEE level, province, or industry |
Organisations (Procurement Bodies)
| Endpoint | Method | Description |
|---|---|---|
| /v1/organizations/{id} | GET | Procurement body profile with contact information |
| /v1/organizations/{id}/tenders | GET | Tenders issued by a specific procurement body |
Meta
| Endpoint | Method | Description |
|---|---|---|
| /v1/meta/status | GET | API health and data freshness information |
| /v1/meta/provinces | GET | List of provinces with active tender counts |
| /v1/meta/categories | GET | List of procurement categories with tender counts |
| /v1/meta/usage | GET | Your API usage statistics across all keys |
Pagination
All list endpoints are paginated with a page-based cursor system. You control pagination with page and pageSize query parameters. The response meta includes everything you need to navigate: page, pageSize, totalCount, totalPages, hasNext, and hasPrev.
1GET /v1/tenders?status=OPEN&page=2&pageSize=50TEXT
Page size defaults to 20 items and can be set up to 100. All three official SDKs implement pagination iterators that handle page traversal automatically.
Rate Limiting
Rate limit status is returned in both HTTP response headers and the response body's meta.rateLimit object:
- Headers:
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset,X-RateLimit-Policy - Body:
meta.rateLimit.limit,meta.rateLimit.remaining,meta.rateLimit.reset,meta.rateLimit.policy
When a rate limit is exceeded, the API returns a 429 status with either RATE_LIMIT_DAILY_EXCEEDED or RATE_LIMIT_MONTHLY_EXCEEDED error code.
Error Codes
| HTTP Status | Code | Description |
|---|---|---|
| 400 | BAD_REQUEST | Invalid request parameters or malformed input |
| 401 | UNAUTHORIZED | Missing or invalid API key |
| 403 | FORBIDDEN / KEY_NOT_ACTIVE / KEY_EXPIRED | Key not active, expired, or lacks permissions |
| 404 | NOT_FOUND | The requested resource does not exist |
| 409 | CONFLICT / KEY_LIMIT_REACHED | Key limit reached for your plan tier |
| 429 | RATE_LIMIT_DAILY_EXCEEDED / RATE_LIMIT_MONTHLY_EXCEEDED | Rate limit exceeded |
| 500 | INTERNAL_ERROR | Server error — please retry with exponential backoff |
| 502 | SERVICE_UNAVAILABLE | Service temporarily unavailable |
Sparse Fields
Reduce response payload size by specifying only the fields you need with the fields query parameter:
1GET /v1/tenders?fields=tenderId,title,status,closingDate,estimatedValueTEXT
This is particularly useful for list endpoints where you may only need a subset of fields for display purposes — for example, populating a table or a dropdown selector without loading the full tender object.
Filtering Parameters
List endpoints support a common set of filter parameters. The exact set varies by resource, but the most widely supported are:
| Parameter | Type | Applies To |
|---|---|---|
| status | string | Filter by tender status: OPEN, CLOSED, AWARDED, CANCELLED |
| province | string | Filter by province name (e.g. 'Gauteng', 'Western Cape') |
| category | string | Filter by procurement category slug |
| minAmount / maxAmount | number | Filter by contract value range (awards) |
| minValue / maxValue | number | Filter by estimated value range (tenders) |
| beeLevel | string | Filter by B-BBEE contributor level |
| sort | string | Sort field with optional '-' prefix for descending order |
| q | string | Free-text search query |
A Typical Integration Walkthrough
A common first project for developers new to the API is a simple internal alert: notify a sales or bid team whenever a new tender opens in a specific province and category combination that matches their business. Building this well means combining several of the pieces covered above rather than any single endpoint in isolation. You would start with /v1/tenders, filtered by province, category, and status=OPEN, using the sort parameter to order by publication or closing date. Because this kind of check typically runs on a schedule rather than in response to a user action, keeping the fields parameter narrow — just the identifiers, title, and closing date you need to decide whether to alert someone — reduces both the payload size and the load on your own rate limit. From there, a scheduled job comparing the current result set against the previous run's cached tender IDs is enough to detect what's genuinely new, without needing to re-process the full list every time.
For a more involved integration — say, enriching your own CRM with company intelligence — you would combine the /v1/companies/{name} endpoint with the /v1/awards endpoint filtered by supplier, giving you both the company's registration-level detail and its historical award record in a single workflow. Whatever you build, it pays to design your integration around the assumption that the underlying data will occasionally be incomplete or delayed for a specific record — procurement data sourced from dozens of government portals is not always perfectly consistent — so defensive handling of missing fields is worth the small amount of extra code it takes upfront.
Getting Started
The quickest way to start exploring the API is through the official SDKs, which handle authentication, pagination, error handling, and retry logic:
- JavaScript / TypeScript SDK — github.com/Tenders-SA/js (
@tenders-sa-org/sdk-json npm) - Python SDK — github.com/Tenders-SA/python (
tendersa-sdkon PyPI) - CLI — github.com/Tenders-SA/cli (
@tenders-sa-org/clion npm)
For direct API access, the full API reference is available at tenders-sa.org/developers/docs. API keys can be generated at tenders-sa.org/developers/api-keys.
Tags
Based on this article's topics, here are some current tenders that might interest you
THE APPOINTMENT OF A SERVICE PROVIDER TO SUPPLY AND DELIVER INFORMATION TECHNOLOGY (IT) EQUIPMENT FROM SUPPLIERS LISTED ON THE SITA RFB 740 TRANSVERSAL CONTRACT- IN THE INLAND REGION FOR THE DEPARTMENT OF FORESTRY, FISHERIES, AND THE ENVIRONMENT (DFFE).
This Request for Information (RFI) invites qualified vendors, advisors and technology providers to submit information on tools, models, workflows and enablement services required to close these identified gaps and integrate with the existing Enerweb ETRM, phased across Day-1 go-live (Phase 1), controlled expansion (Phase 2, Year 1–2) and a mature state (Phase 3, Year 3+).
Feasibility Study on Hydrogen-Powered Mining Equipment Conversion using Hydrogen Combustion Technology for Surface and Underground Mining.
VIRTUALIZATION TECHNOLOGY REQUIREMENTS AND CAPABILITIES FOR SABC
REQUEST FOR INFORMATION: CLOUD-HOSTED OBSERVABILITY SOLUTION FOR THE ROAD ACCIDENT FUND (RAF) TO SUPPORT ENTERPRISE-WIDE MONITORING, ANALYTICS AND OPERATIONAL INTELLIGENCE ACROSS ITS HYBRID TECHNOLOGY ENVIRONMENT
APPOINTMENT OF A SERVICE PROVIDER TO ROLL OUT AND IMPLEMENT A FOUNDRY TRAINING AND FURNACE REPAIRS PROJECT AT THE DOWNSTREAM ALUMINIUM CENTRE FOR TECHNOLOGY (DACT) TO IMPROVE METAL BENEFICIATION SKILLS FOR A PERIOD OF SIX MONTHS.
Want to see all available tenders?
Browse All Tenders →Share this article
The Tenders-SA Developer API: Programmatic Access to South African Procurement Data
A technical guide to the Tenders-SA Developer API — authentication, endpoints, pagination, rate limiting, error handling, and sparse field support. For developers building on top of SA public procurement data.