Using the Tenders-SA JavaScript SDK to Access SA Procurement Data
A practical guide to the @tenders-sa-org/sdk-js npm package — installation, client setup, resource methods, pagination iterators, error handling, retry configuration, and sparse fields.
Building with SA Procurement Data in JavaScript and TypeScript
The @tenders-sa-org/sdk-js package provides a typed, idiomatic TypeScript client for the Tenders-SA Developer API. It handles authentication, pagination, error mapping, rate limit tracking, and retry with exponential backoff — so you can focus on integrating procurement data into your application rather than building HTTP client infrastructure.
The SDK is open source under the MIT license and published on npm. The source code is available at github.com/Tenders-SA/js.
Installation
1npm install @tenders-sa-org/sdk-jsBASH
The SDK requires Node.js 18+ (for native fetch support) and works with TypeScript 5+ for full type safety. No additional HTTP client libraries are required.
Quick Start
Create a client with your API key and start querying data within seconds:
1import { TendersaClient } from '@tenders-sa-org/sdk-js' 2 3const client = new TendersaClient({ apiKey: 'tsa_prod_your_key' }) 4 5// List open tenders in the Western Cape 6const tenders = await client.tenders.list({ 7 status: 'OPEN', 8 province: 'Western Cape', 9}) 10 11for (const tender of tenders.data) { 12 console.log(`${tender.title} — ${tender.closingDate}`) 13} 14 15// Get a single tender's AI analysis 16// ... (truncated)TYPESCRIPT
Client Configuration
The TendersaClient accepts several configuration options beyond the API key:
1const client = new TendersaClient({ 2 apiKey: 'tsa_prod_your_key', 3 baseUrl: 'https://api.tenders-sa.org', // default 4 timeout: 30_000, // 30 seconds (default) 5 retry: { maxRetries: 3 }, // exponential backoff 6})TYPESCRIPT
Resource Methods
The SDK is organised into five resource classes, each mapped to a section of the API.
Tenders
1// List with filters 2const { data, meta } = await client.tenders.list({ 3 status: 'OPEN', 4 category: 'Construction', 5 province: 'Gauteng', 6 sort: '-closingDate', 7}) 8 9// Get detail with AI analysis 10const tender = await client.tenders.get('tender_001') 11 12// Related resources 13const docs = await client.tenders.documents('tender_001') 14const awards = await client.tenders.awards('tender_001') 15const timeline = await client.tenders.timeline('tender_001') 16// ... (truncated)TYPESCRIPT
Awards
1// List awards with filters 2const { data } = await client.awards.list({ 3 province: 'Western Cape', 4 beeLevel: 'Level 1', 5 minAmount: 1_000_000, 6}) 7 8// Get a single award 9const award = await client.awards.get('award_001') 10 11// Aggregated analytics 12const analytics = await client.awards.analytics({ 13 groupBy: 'province', 14 from: '2025-01-01', 15 to: '2025-12-31', 16// ... (truncated)TYPESCRIPT
Companies
1// Company intelligence profile (by exact name) 2const company = await client.companies.get('BuildCorp SA') 3 4// Search companies 5const results = await client.companies.search({ 6 q: 'Construction', 7 beeLevel: 'Level 1', 8 province: 'Gauteng', 9})TYPESCRIPT
Organisations (Procurement Bodies)
1const org = await client.organizations.get('org_001') 2const tenders = await client.organizations.tenders('org_001', { 3 status: 'OPEN', 4})TYPESCRIPT
Meta
1const status = await client.meta.status() 2const provinces = await client.meta.provinces() 3const categories = await client.meta.categories() 4const usage = await client.meta.usage()TYPESCRIPT
Pagination
List endpoints return a single page by default. For traversing multiple pages, the SDK provides a PaginatedAsyncIterator that yields arrays of items per page:
1const paginator = client.tenders.listPages({ 2 status: 'OPEN', 3 category: 'Construction', 4}) 5 6for await (const page of paginator.pages()) { 7 for (const tender of page) { 8 console.log(tender.title) 9 } 10} 11 12// Control page size and max pages 13const awards = client.awards.listPages( 14 { province: 'Gauteng' }, 15 { pageSize: 50, maxPages: 10 } 16// ... (truncated)TYPESCRIPT
Error Handling
The SDK throws typed errors for every API response status. You can catch specific error types to handle different failure modes:
1import { 2 TendersaError, 3 AuthError, 4 NotFoundError, 5 RateLimitError, 6} from '@tenders-sa-org/sdk-js' 7 8try { 9 const result = await client.tenders.get('nonexistent') 10} catch (err) { 11 if (err instanceof AuthError) { 12 console.error('Invalid API key') 13 } else if (err instanceof NotFoundError) { 14 console.error('Tender not found') 15 } else if (err instanceof RateLimitError) { 16// ... (truncated)TYPESCRIPT
Every error exposes status (HTTP status code), code (machine-readable, e.g. NOT_FOUND), message (human-readable), requestId (for tracing with support), and docs (link to error documentation).
Rate Limit Tracking
The client stores the most recent rate limit snapshot, accessible via client.lastRateLimit:
1console.log(client.lastRateLimit) 2// { limit: 500, remaining: 498, reset: '2026-01-02T00:00:00Z', policy: 'daily' }TYPESCRIPT
Retry Configuration
The SDK retries on transient failures (network errors, 500-series responses) with exponential backoff. Configure retry behaviour through the client constructor:
1const client = new TendersaClient({ 2 apiKey: 'tsa_prod_your_key', 3 retry: { 4 maxRetries: 5, // default: 3 5 baseDelayMs: 200, // default: 1000ms 6 maxDelayMs: 10_000, // default: 30000ms 7 }, 8})TYPESCRIPT
Sparse Fields
Reduce response payload size by specifying only the fields you need. Supported on all list methods:
1const { data } = await client.tenders.list({ 2 fields: 'tenderId,title,status,closingDate', 3})TYPESCRIPT
Links and Resources
The full SDK source code is on GitHub at github.com/Tenders-SA/js. The package is published to npm as @tenders-sa-org/sdk-js. The complete API reference is available at tenders-sa.org/developers/docs.
The repository includes the full TypeScript source with type definitions exported, unit tests, and a comprehensive README with examples for every endpoint. Issues and pull requests are welcome.
Tags
Based on this article's topics, here are some current tenders that might interest you
Request for Supply and Delivery of PAT Materials to appropriate workshop clothing to Technical, Comprehensive and Agricultural Schools: Lot1 - Supply, delivery and installation of Equipment and Tools for Civil, Electrical, Mechanical Technology Specialisations and Engineering Graphics and Design (EGD): Lot2 - Supply and Delivery of Practical Assessment Task (PAT) Materials to Technical, Comprehensive and Agricultural Schools: Lot3 - Supply and Delivery of Personal Protective Clothing for Teachers to Technical and Comprehensive Schools in the Free State for the period of Three Financial Years from the date of approval
REPLACEMENT OF EXISTING PIPE SYSTEMS THROUGH TRENCHLESS TECHNOLOGY FOR A PERIOD ENDING 30 JUNE 2029
Conducting information and Communication Technology (ICT) audits on an as and when required basis for a period of thirty-six (36) months
Provisioning of Magik and ESRI Technology Maintenance and Support for a period of two (2) years -Re-Issue
Request for information on commercially available and/or proven technology for re-engineering of the OPC DA (Data Access) communication protocol for control systems that are impacted by the Microsoft security changes for systems using the Windows operating system and have the OPC classic architecture infrastructure based on DCOM based communication (where OEM support is no longer available as they have exited the business).
THE APPOINTMENT OF ONE SERVICE PROVIDER TO SUPPLY, INSTALL, CONFIGURE AND PROVIDE TECHNICAL TRAINING OF INFORMATION TECHNOLOGY (IT) SERVICE HELPDESK SYSTEM FOR THE DEPARTMENT OF FORESTRY, FISHERIES, AND THE ENVIRONMENT (DFFE) FOR A PERIOD OF TWO (2) YEARS.
Want to see all available tenders?
Browse All Tenders →Share this article
Using the Tenders-SA JavaScript SDK to Access SA Procurement Data
A practical guide to the @tenders-sa-org/sdk-js npm package — installation, client setup, resource methods, pagination iterators, error handling, retry configuration, and sparse fields.