# /saetenders/tenders/search

`POST /api/saetenders/tenders/search`

Price: 20 credits

Search South African public tenders on eTenders within one status bucket — advertised, awarded, closed or cancelled — by industry category, province, organ of state, tender type, electronic submission, tender number and awarded supplier. Returns each tender with its buyer contact, dates, bid documents and, once made, the award and the published list of bidders.

## How to use it

`status` is mandatory; `awarded` additionally needs one narrowing filter, because the source cannot list its whole awarded set. There is no free-text search over titles — narrow with the catalogue filters and use `tender_number` for a known reference. `department` must match an eTenders organ-of-state name exactly (case does not matter) and is answered with 422 otherwise; take it from a result row. `ocid` on every row resolves through saetenders/tenders.

## Parameters

- `access-token` (string, required)

## Request body

- `timeout` (integer) — Max scrapping execution timeout (in seconds) (default: 300; min: 20; max: 1500)
- `status` (string, required) — Which tenders to list (one of: "advertised", "awarded", "closed", "cancelled")
- `category` (string, nullable) — Industry category (one of: "Accommodation", "Activities auxiliary to financial service and insurance activities.", "Activities of head offices; management consultancy activities", "Activities of households as employers of domestic personnel", "Administrative and support activities", "Advertising and market research", "Agricultural Products and Services", "Air transport", "Architectural and engineering activities; technical testing and analysis", "Arts, entertainment and recreation", "Civil engineering", "Computer programming, consultancy and related activities", "Construction", "Construction of buildings", "Creative, arts and entertainment activities", "Disposals: General", "Education", "Electricity, gas, steam and air conditioning", "Employment activities", "Financial and insurance activities", "Financial service activities, except insurance and pension funding", "Food and beverage service activities", "Human health activities", "Human health and social work activities", "Information and communication", "Information service activities", "Insurance, reinsurance and pension funding, except compulsory social security", "Land transport and transport via pipelines", "Legal and accounting activities", "Libraries, archives, museums and other cultural activities", "Manufacture of basic metals", "Manufacture of chemicals and chemical products", "Manufacture of coke and refined petroleum products", "Manufacture of computer, electronic and optical products", "Manufacture of electrical equipment", "Manufacture of fabricated metal products, except machinery and equipment", "Manufacture of furniture", "Manufacture of machinery and equipment n.e.c.", "Manufacture of motor vehicles, trailers and semi-trailers", "Manufacture of other non-metallic mineral products", "Manufacture of paper and paper products", "Manufacture of rubber and plastics products", "Manufacture of textiles", "Manufacturing", "Mining and quarrying", "Mining of coal and lignite", "Mining support service activities", "Motion picture, video and television programme production, sound recording and music publishing activities", "Office administrative, office support and other business support activities", "Other manufacturing", "Other personal service activities", "Other professional, scientific and technical activities", "Other service activities", "Postal and courier activities", "Printing and reproduction of recorded media", "Professional, scientific and technical activities", "Programming and broadcasting activities", "Publishing activities", "Real estate activities", "Remediation activities and other waste management services", "Rental and leasing activities", "Repair and installation of machinery and equipment", "Residential care activities", "Scientific research and development", "Security and investigation activities", "Services to buildings and landscape activities", "Services: Building", "Services: Civil", "Services: Electrical", "Services: Functional (Including Cleaning and Security Services)", "Services: General", "Services: Professional", "Sewerage", "Specialised construction activities", "Sports activities and amusement and recreation activities", "Supplies: Clothing/Textiles/Footwear", "Supplies: Computer Equipment", "Supplies: Electrical Equipment", "Supplies: General", "Supplies: Medical", "Supplies: Perishable Provisions", "Supplies: Stationery/Printing", "Telecommunications", "Transportation and storage", "Travel agency, tour operator, reservation service and related activities", "Warehousing and support activities for transportation", "Waste collection, treatment and disposal activities; materials recovery", "Water collection, treatment and supply", "Water supply; sewerage, waste management and remediation activities", "Water transport", "Wholesale and retail trade and repair of motor vehicles and motorcycles")
- `province` (string, nullable) — Province, or National (one of: "Eastern Cape", "Free State", "Gauteng", "KwaZulu-Natal", "Limpopo", "Mpumalanga", "National", "North West", "Northern Cape", "Western Cape")
- `department` (string, nullable) — Organ of state exactly as eTenders names it (examples: "uMhlathuze Municipality", "Johannesburg Water"; minLength: 1)
- `tender_type` (string, nullable) — Tender type (one of: "Request for Bid(Open-Tender)", "Request for Bid(Limited-Tender)", "Request for Quotation", "Request for Information", "Request for Proposal", "Expression of Interest", "SITA Contract", "Transversal Contract", "Participation", "Deviation", "Emergency Procurement", "Procurement from other OoS", "Restricted Bidding", "RFQ Above Threshold", "Single source bidding", "Sole source bidding", "State Attorney Services")
- `esubmission` (boolean, nullable) — Whether bids are submitted electronically
- `tender_number` (string, nullable) — Part of the tender number (examples: "UMH1792"; minLength: 1)
- `company` (string, nullable) — Part of the awarded supplier name, on awarded tenders only (examples: "water"; minLength: 1)
- `count` (integer, required) — Max number of tenders to return (min: 1; max: 2000)

## Response

### 200 — Successful Response

- `@type` (string) (default: "SaetendersTenderCard")
- `id` (integer, required)
- `ocid` (string, required)
- `tender_number` (string, nullable)
- `status` (string, nullable)
- `category` (string, nullable)
- `tender_type` (string, nullable)
- `department` (string, nullable)
- `province` (string, nullable)
- `published_at` (integer, nullable)
- `closing_at` (integer, nullable)
- `validity_days` (integer, nullable)
- `is_esubmission` (boolean, nullable)
- `is_two_envelope` (boolean, nullable)
- `has_briefing_session` (boolean, nullable)
- `is_briefing_compulsory` (boolean, nullable)
- `briefing_at` (integer, nullable)
- `briefing_venue` (string, nullable)
- `delivery_location` (string, nullable)
- `street` (string, nullable)
- `suburb` (string, nullable)
- `town` (string, nullable)
- `postal_code` (string, nullable)
- `conditions` (string, nullable)
- `contact_name` (string, nullable)
- `contact_email` (string, nullable)
- `contact_telephone` (string, nullable)
- `contact_fax` (string, nullable)
- `documents` (array) (default: [])
  - `@type` (string) (default: "SaetendersDocument")
  - `id` (string, required)
  - `name` (string, nullable)
  - `extension` (string, nullable)
  - `url` (string, required)
  - `modified_at` (integer, nullable)
- `bidders` (array) (default: [])
  - `@type` (string) (default: "SaetendersBidder")
  - `id` (integer, required)
  - `name` (string, nullable)
  - `amount` (number, nullable)
  - `currency` (string) (default: "ZAR")
  - `modified_at` (integer, nullable)
- `bidders_list_documents` (array) (default: [])
  - `@type` (string) (default: "SaetendersBiddersListDocument")
  - `id` (integer, required)
  - `name` (string, nullable)
  - `extension` (string, nullable)
  - `url` (string, required)
  - `created_at` (integer, nullable)
- `awards` (array) (default: [])
  - `@type` (string) (default: "SaetendersAward")
  - `id` (integer, required)
  - `supplier` (string, nullable)
  - `enterprise_type` (string, nullable)
  - `amount` (number, nullable)
  - `currency` (string) (default: "ZAR")
  - `points_awarded` (number, nullable)
  - `bee_scoring` (string, nullable)
  - `awarded_at` (integer, nullable)
  - `contact_name` (string, nullable)
  - `contact_telephone` (string, nullable)
  - `created_at` (integer, nullable)
- `awarded_at` (integer, nullable)
- `cancellation_reason` (string, nullable)
- `cancelled_at` (integer, nullable)
- `closure_reason` (string, nullable)
- `closed_at` (integer, nullable)
- `url` (string, required)

## Errors

### 422 — Validation Error

Awarded tenders were requested without a narrowing filter, `company` was combined with another status, or the department name is not one eTenders knows

What to do: Check the fields against this schema. A URN with the wrong prefix is the most common cause.

- `detail` (array)
  - `loc` (array, required)
  - `msg` (string, required)
  - `type` (string, required)
  - `input` (any)
  - `ctx` (object)

### 408

The request ran past its time limit

What to do: Raise `timeout` in the request body, up to the maximum this endpoint documents. Lowering `count` or turning off the `with_*` flags also helps, because less work finishes sooner.

### 412

The source failed to list awarded tenders for this filter combination

What to do: Retrying will not help: either the entity does not exist, or the input points at a different one.

### 429

Too many requests: a rate limit or a usage window is exhausted

What to do: When the response carries an X-Retry-After header, wait that many seconds and retry: the same number is in the body as `detail.retry_after`, and the limit clears once that window passes. The message in the body names the limit that was hit.

### 500

Something broke on our side

What to do: Retrying will not help. If it keeps happening, send us the X-Request-ID from the response headers.

### 529

Rate limit reached, or the endpoint is overloaded

What to do: Wait at least 30 seconds, then retry.

## Response envelope

Success: Array of objects (may be empty if no results)

Error: Error may coexist with partial results if it occurs mid-execution. Check X-Error header and status code.

Every response carries these headers:

- `X-Error` — Error message text (present only on error)
- `X-Request-ID` — Unique request identifier
- `X-Execution-Time` — Execution time in seconds
- `X-Result-Count` — How many records the body carries. 0 means an empty result, which is a normal answer and not by itself an error. A non-zero count can come back together with X-Error when the failure happened partway through — read this header and X-Error independently.
- `X-Total-Available-Results` — How many records exist for this query, when the endpoint can say. On a `dry_run` request this is the answer and the body is empty. It saturates: the endpoint's documented maximum means 'at least that many', any smaller number is exact.
- `X-Warning` — Present when the request body carried keys this endpoint does not document. They were ignored, so any filter you meant to apply through them did not apply. Check the spelling against this schema and retry.
- `X-Retry-After` — Seconds to wait before retrying. Present only on 429.

