South African Tender Data from the Terminal: The Tenders-SA CLI
A practical guide to the @tenders-sa-org/cli command-line tool — installation, configuration, commands for tenders, awards, companies, and meta endpoints, output formatting, and CI/CD integration.
SA Procurement Data at Your Terminal
The @tenders-sa-org/cli tool provides terminal access to the Tenders-SA Developer API. It supports every API endpoint as a command, filters tenders and awards by province, category, value, and date range, outputs structured JSON suitable for piping into other tools, and stores credentials locally for persistent sessions.
The CLI is open source under the MIT license and published on npm. The source code is available at github.com/Tenders-SA/cli.
Most people first encounter Tenders-SA data through the website's search and filter interface. That works well for a one-off lookup, but it breaks down the moment you want to do something repeatable: check every morning whether a new tender has appeared in your category, feed award data into an internal spreadsheet, or wire tender alerts into a Slack channel. A command-line tool fits that kind of workflow far better than a browser tab, because it can be scripted, scheduled, and composed with the dozens of other small utilities developers already use daily. That is the gap the CLI is built to fill: the same underlying data as the API, but shaped for a terminal, a cron job, or a CI pipeline rather than a human clicking through pages.
Installation
Install globally via npm, or run directly without installation using npx:
1# Install globally (recommended for regular use) 2npm install -g @tenders-sa-org/cli 3 4# Or run without installation 5npx @tenders-sa-org/cli tenders listBASH
Quick Start
Configure your API key once, then start querying data immediately:
1# Configure your API key (stored in ~/.tendersa/config.json) 2tendersa config set tsa_prod_your_key 3 4# Check API health 5tendersa meta status 6 7# List open tenders in the Western Cape 8tendersa tenders list --status OPEN --province "Western Cape" 9 10# Get tender details 11tendersa tenders get tender_001 12 13# AI-powered semantic search 14tendersa tenders search "road construction" 15 16// ... (truncated)BASH
Notice how little ceremony is involved in that Quick Start block: one command to store your key, then five commands that each answer a different real-world question. A procurement manager scanning for opportunities in their province runs the tenders list command with a --status and --province filter first thing each morning. A business-development analyst preparing a competitor briefing runs companies get before a client meeting to pull a supplier's award history without digging through PDFs. A developer building an internal dashboard runs meta status in a health check script to confirm the underlying data feed is fresh before trusting anything downstream. The commands are simple individually, but the value comes from how easily they slot into whatever workflow you already have — a shell alias, a scheduled script, or a larger data pipeline.
Configuration
The CLI stores a single configuration file at ~/.tendersa/config.json containing your API key. Manage it through the config command:
1tendersa config set tsa_prod_your_key # Save API key 2tendersa config get # Show current key (masked)BASH
The API key is also configurable via the TENDERSA_API_KEY environment variable, which takes precedence over the config file. This is useful for CI/CD environments where you prefer not to write credentials to disk:
1export TENDERSA_API_KEY=tsa_prod_your_key 2tendersa tenders list --status OPENBASH
Splitting configuration between a local file and an environment variable is a deliberate design choice rather than redundancy. On a developer's own laptop, saving the key once with tendersa config set and forgetting about it is the more convenient path — you do not want to re-export an environment variable every time you open a new terminal tab. In a CI/CD runner or a shared server, on the other hand, writing a production API key to a plaintext config file on disk is a real security concern, particularly if that disk is a container image that might get cached or shared. Setting TENDERSA_API_KEY as a pipeline secret and letting it override the config file gives you the best of both without maintaining two separate code paths in your own scripts.
Command Reference
The CLI mirrors the API resources. Every command outputs JSON to stdout, with errors and progress messages going to stderr.
That stdout/stderr separation is worth calling out explicitly, because it is what makes the CLI genuinely scriptable rather than just a pretty wrapper around HTTP calls. If a command hits a rate limit, a bad filter combination, or a network timeout, the error text is written to stderr and the command exits with a non-zero status code, leaving stdout empty or untouched. That means a script that pipes CLI output into jq or a file redirect will not silently ingest an error message as if it were data — a small detail, but one that saves real debugging time once you are running the CLI unattended in a scheduled job rather than watching it interactively.
Tenders
1# List tenders with filters 2tendersa tenders list \ 3 --status OPEN \ 4 --province Gauteng \ 5 --category Construction \ 6 --min-value 1000000 \ 7 --closing-after 2026-06-01 \ 8 --limit 20 \ 9 --sort -closingDate 10 11# Get detailed tender with AI analysis 12tendersa tenders get tender_001 13 14# Semantic search across all tenders 15tendersa tenders search "road construction" 16// ... (truncated)BASH
List filter options:
| Option | Description |
|---|---|
| --status | Filter by status: OPEN, CLOSED, AWARDED, CANCELLED |
| --province | Filter by province (e.g. Gauteng, Western Cape) |
| --category | Filter by category (e.g. Construction, IT) |
| --closing-after / --closing-before | Filter by closing date range (ISO 8601) |
| --min-value / --max-value | Filter by estimated value range |
| --sort | Sort field: closingDate, -closingDate, value, -value |
| --page | Page number (default: 1) |
| --limit | Items per page (default: 20, max: 100) |
In practice, the tenders list command with a stack of filters is the workhorse of the whole CLI. Combining --province, --category, and --min-value lets a construction firm narrow a national feed of thousands of tenders down to the handful of Gauteng infrastructure opportunities above a size threshold worth their bid team's time. The --closing-after filter is particularly useful in a scheduled script: run it daily comparing against yesterday's date and you effectively get a rolling feed of newly-relevant tenders rather than re-scanning everything each time. The tenders search command serves a different purpose to list — where list filters on structured fields like province or category, search runs a semantic query over tender text itself, which is useful when you know roughly what you are looking for ('road construction', 'school nutrition') but do not know which exact category code it was filed under. The documents, analysis, and value-estimate subcommands exist for the moment after you have found a tender of interest and want to go deeper — pulling the underlying tender documents, an AI-generated summary of the requirements, or an estimated value range without leaving the terminal.
Awards
1# List awards with filters 2tendersa awards list \ 3 --supplier-name "BuildCorp" \ 4 --province Gauteng \ 5 --min-amount 500000 \ 6 --from 2025-01-01 \ 7 --to 2025-12-31 \ 8 --limit 50 9 10# Get award details 11tendersa awards get award_001BASH
Award list options include --supplier-name, --enterprise-type (SMME, QSE, etc.), --bee-level, --province, --category, --min-amount, --max-amount, --from, --to, --page, and --limit.
The awards resource answers a different question to the tenders resource: not 'what is currently open for bidding' but 'who has already won, and on what terms.' This is where the CLI becomes genuinely useful for competitive intelligence. Filtering awards list by --supplier-name for a known competitor shows their recent contract wins, in which provinces, and roughly what scale of business they are picking up. Filtering instead by --enterprise-type and --bee-level lets an SMME gauge how much of the award activity in their category is going to businesses of a similar size and B-BBEE profile to their own, which is a useful sanity check before investing significant bid-preparation time in a category that historically favours much larger firms. Because the output is JSON, none of this requires manually reading through award notices — a short script can aggregate award amounts by province or by month in a few lines.
Companies
1# Full company intelligence profile (by exact name) 2tendersa companies get "BuildCorp SA" 3 4# Search companies 5tendersa companies search "Construction"BASH
The company profile includes award history, contract values, enterprise type, BEE level, and compliance data aggregated from public procurement records.
The companies commands are the natural next step after finding an interesting award: rather than looking at a single contract in isolation, you can pull the full picture of a supplier's public sector track record. A due-diligence analyst vetting a potential joint venture partner might run companies get on the candidate before signing anything, checking that their claimed contract history matches what is on record and that their reported BEE level and compliance status are consistent with what the partner told you directly. companies search is useful earlier in the process, when you know roughly what kind of supplier you are looking for by name fragment or keyword but do not yet have an exact company name to query.
Meta
1tendersa meta status # API health and data freshness 2tendersa meta provinces # Tender counts by province 3tendersa meta categories # Tender counts by category 4tendersa meta usage # Your API usage statisticsBASH
The four meta commands are small but they matter more than their size suggests, particularly in automated contexts. meta status is the command you run before trusting any other output — if the underlying data feed has stalled, you want a health check to catch that before your dashboard silently shows stale numbers as if they were current. meta provinces and meta categories are useful for building any kind of summary view, letting you show a breakdown of tender volume without needing to page through every single record and count them yourself. meta usage is the one to check when a script that has run reliably for months suddenly starts failing — often the answer is simply that you are approaching your plan's request limit.
Output and Piping
All commands output JSON to stdout, making them safe to pipe into other tools. Error messages go to stderr so they do not interfere with piped data:
1# Extract tender titles using jq 2tendersa tenders list --status OPEN --limit 5 | jq '.data[].title' 3 4# Count awards by province 5tendersa awards list --limit 100 | jq '[.data[].province] | sort | unique | length' 6 7# Export to file 8tendersa tenders list --status OPEN --limit 1000 > tenders.json 9 10# Pipe through a Python script for custom analysis 11tendersa tenders list --status OPEN | python analyze.pyBASH
None of these piping examples require any special support from the CLI itself — they work simply because the tool commits to always emitting clean, well-formed JSON on stdout and nothing else. That reliability is what lets you treat the CLI as a building block rather than an end in itself. A common pattern for teams already using Tenders-SA data internally is to run a scheduled export overnight, storing the day's tender and award JSON in a data lake or a simple flat-file archive, and then letting internal BI tools query that archive rather than hitting the API directly for every report. This keeps API usage predictable and gives you a historical record of exactly what the data looked like on any given day, which the live API alone will not provide once tenders close or get updated.
CI/CD and Automation
The CLI is designed for use in CI/CD pipelines and automated scripts. Use the TENDERSA_API_KEY environment variable to avoid writing credentials to disk:
1# GitHub Actions example 2- name: Check tender availability 3 run: | 4 npm install -g @tenders-sa-org/cli 5 export TENDERSA_API_KEY=${{ secrets.TENDERSA_API_KEY }} 6 7 # Check if there are new tenders in our category 8 COUNT=$(tendersa tenders list \ 9 --status OPEN \ 10 --category Construction \ 11 --closing-after $(date -I) \ 12 | jq '.meta.totalCount') 13 14 echo "Open construction tenders: $COUNT" 15 16// ... (truncated)BASH
Use Cases
- Quick tender checks: Check active tenders in a province without opening a browser. The CLI loads data in under a second.
- CI/CD integration: Embed tender data into your internal dashboards and reporting pipelines. The CLI's JSON output integrates naturally with GitHub Actions, Jenkins, and similar platforms.
- Market monitoring: Script periodic scans of award activity in your sector. Use cron or scheduled CI jobs to run the CLI and export results.
- Data export: Pipe tender data into CSV, JSON processors, or analysis tools like
jq,pandas, or custom scripts.
The GitHub Actions example above is a good illustration of the broader pattern worth adopting: rather than a person remembering to check the site each morning, a scheduled workflow does the checking and only surfaces a signal — a notification, a Slack message, a GitHub Actions output variable — when there is something worth a human's attention. This is the difference between treating tender monitoring as a manual chore and treating it as infrastructure. Once the check is codified as a script using the CLI, it can be version-controlled, reviewed, and adjusted by anyone on the team, rather than living as institutional knowledge in one person's daily routine.
Frequently Asked Questions
- Q: Do I need a paid API plan to use the CLI?
A: The CLI itself is free and open source; it is simply a terminal interface to the Tenders-SA Developer API. Your access level and rate limits are governed by whatever API key you configure, so check the developer docs for the plan tiers available. - Q: Can I use the CLI without Node.js installed?
A: The package is distributed via npm, so a working Node.js and npm installation is required, whether you install it globally or run it on demand with npx. - Q: Is the JSON output stable across versions?
A: The CLI's output mirrors the underlying API response shapes documented in the developer reference, so scripts built against a documented field should continue to work across CLI updates. As with any API-backed tool, pin a specific version in CI pipelines if you want to control exactly when you adopt changes. - Q: Can I contribute to the CLI or report a bug?
A: Yes. The project is open source under the MIT license, and issues and pull requests are welcome on the GitHub repository linked below.
Links and Resources
The full CLI source code is on GitHub at github.com/Tenders-SA/cli. The package is published to npm as @tenders-sa-org/cli. The complete API reference is available at tenders-sa.org/developers/docs.
The repository includes the full TypeScript source code, the CLI command definitions, and a README with examples for every command. Issues and pull requests are welcome.
Tags
Based on this article's topics, here are some current tenders that might interest you
REPLACEMENT OF EXISTING PIPE SYSTEMS EMPLOYING SPECIALISED TRENCHLESS CONSTRUCTION TECHNOLOGY IN THE DRAKENSTEIN MUNICIPAL AREA FOR A PERIOD UP TO 30 JUNE 2029
Request For Information (RFI) CSIR is requesting information from interested service providers, product suppliers, research organisations and technology developers on: Radio Frequency Electronic Warfare (EW) payloads for unmanned airborne and spaceborne platforms
Request for supply, delivery, commissioning and maintenance of a Dicom dry imaging printer with dry laser printing technology (digital x-ray printers) for Eastern Cape facilities for 36 months.
REQUEST FOR TOWN PLANNING & ENVIRONMENTAL SERVICES AT SABIE EXTENSION 19 (FORESTRY INDUSTRIAL TECHNOLOGY PARK) FOR THE APPROVAL OF THE LAYOUT PLAN AND REQUIRED ENVIRONMENTAL AUTHORISATION IN SABIE, THABA CHWEU LOCAL MUNICIPALITY, MPUMALANGA PROVINCE FOR A PERIOD OF NINE (09) MONTHS
ENTERPRISE CONTENT MANAGEMENT (ECM) STRATEGY, GOVERNANCE FRAMEWORK, TARGET ARCHITECTURE, TECHNOLOGY ROADMAP AND NARSSA-COMPLIANT ORGANISATIONAL FILE PLAN FOR A DURATION OF SIX(6) MONTHS
Appointment of a service provider to supply, installation and commissioning of an acoustic sound insulation system for executive offices in the Department of Science, Technology and Innovation
Want to see all available tenders?
Browse All Tenders →Share this article
South African Tender Data from the Terminal: The Tenders-SA CLI
A practical guide to the @tenders-sa-org/cli command-line tool — installation, configuration, commands for tenders, awards, companies, and meta endpoints, output formatting, and CI/CD integration.