Integrate with Chance AI
Developer portal
Chance AI Public API
v1.0.0
Search and retrieve publicly listed opportunities.
https://api.chance.africaAuthentication
Send your API key in the X-API-Key header:X-API-Key: ca_live_…
Requests without a valid key are rejected with 401 Unauthorized.
Endpoints
GET
/api/v1/opportunitiesRequires API key
Search publicly listed opportunities.
Returns a paginated page of approved opportunities.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| query | query | stringmin length 1 · max length 200 | No | Free-text search phrase matched against title, description and tags. |
| type | query | job | study | training | tender | other | No | Opportunity category. Omit to search across every category. |
| mode | query | keyword | hybrid | enhanced | No | Search execution mode: 'keyword' for lexical matching, 'hybrid' for combined keyword and vector ranking, or 'enhanced' for multilingual and intent-enhanced matching. Defaults to 'hybrid'. |
| category | query | stringmin length 1 · max length 120 | No | Sector or category label, for example 'Engineering' or 'Security Services'. |
| location | query | stringmin length 1 · max length 120 | No | Free-text location filter matched against the opportunity location. |
| province | query | stringmin length 1 · max length 120 | No | South African province filter, applied to tender listings. |
| organOfState | query | stringmin length 1 · max length 120 | No | Issuing organ of state, applied to tender listings. |
| postedFrom | query | string (date-time) | No | Only include opportunities published on or after this instant. |
| postedTo | query | string (date-time) | No | Only include opportunities published on or before this instant. |
| page | query | integermin 1 · max 200 · default 1 | No | One-based page index. |
| pageSize | query | integermin 1 · max 100 · default 25 | No | Number of records per page. |
Responses
| Status | Body | Description |
|---|---|---|
| 200 | OpportunityListResponse | A page of matching opportunities. |
| 401 | ApiError | The request carried no valid API key. |
| 422 | FastApiValidationError | The query string failed validation. |
| 429 | ApiError | The client exceeded the rate limit for this endpoint. |
| 500 | ApiError | The request could not be completed. |
GET
/api/v1/jobsRequires API key
Search publicly listed job opportunities.
Returns a paginated page of approved job opportunities. Page size is requested with 'limit', not 'pageSize'.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| query | query | stringmin length 1 · max length 200 | No | Free-text search phrase matched against title, description and tags. |
| mode | query | keyword | hybrid | enhanced | No | Search execution mode: 'keyword' for lexical matching, 'hybrid' for combined keyword and vector ranking, or 'enhanced' for multilingual and intent-enhanced matching. Defaults to 'hybrid'. |
| category | query | stringmin length 1 · max length 120 | No | Sector or category label, for example 'Engineering' or 'Security Services'. |
| location | query | stringmin length 1 · max length 120 | No | Free-text location filter matched against the opportunity location. |
| province | query | stringmin length 1 · max length 120 | No | South African province filter, applied to tender listings. |
| organOfState | query | stringmin length 1 · max length 120 | No | Issuing organ of state, applied to tender listings. |
| postedFrom | query | string (date-time) | No | Only include opportunities published on or after this instant. |
| postedTo | query | string (date-time) | No | Only include opportunities published on or before this instant. |
| page | query | integermin 1 · max 200 · default 1 | No | One-based page index. |
| limit | query | integermin 1 · max 100 · default 25 | No | Number of job records per page. |
Responses
| Status | Body | Description |
|---|---|---|
| 200 | OpportunityListResponse | A page of matching job opportunities. |
| 401 | ApiError | The request carried no valid API key. |
| 422 | FastApiValidationError | The query string failed validation. |
| 429 | ApiError | The client exceeded the rate limit for this endpoint. |
| 500 | ApiError | The request could not be completed. |
GET
/api/v1/searchRequires API key
Search publicly listed opportunities by relevance.
Ranks approved opportunities against the search phrase using full-text and fuzzy title matching. Requires 'query'; use listOpportunities to browse without one.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| type | query | job | study | training | tender | other | No | Opportunity category. Omit to search across every category. |
| category | query | stringmin length 1 · max length 120 | No | Sector or category label, for example 'Engineering' or 'Security Services'. |
| location | query | stringmin length 1 · max length 120 | No | Free-text location filter matched against the opportunity location. |
| province | query | stringmin length 1 · max length 120 | No | South African province filter, applied to tender listings. |
| organOfState | query | stringmin length 1 · max length 120 | No | Issuing organ of state, applied to tender listings. |
| postedFrom | query | string (date-time) | No | Only include opportunities published on or after this instant. |
| postedTo | query | string (date-time) | No | Only include opportunities published on or before this instant. |
| page | query | integermin 1 · max 200 · default 1 | No | One-based page index. |
| pageSize | query | integermin 1 · max 100 · default 25 | No | Number of records per page. |
| query | query | stringmin length 1 · max length 200 | Yes | Search phrase. Results are ordered by relevance against title and description rather than by publication date. |
Responses
| Status | Body | Description |
|---|---|---|
| 200 | OpportunityListResponse | A page of matching opportunities, most relevant first. |
| 401 | ApiError | The request carried no valid API key. |
| 422 | ApiError | FastApiValidationError | The query string failed validation. |
| 429 | ApiError | The client exceeded the rate limit for this endpoint. |
| 500 | ApiError | The request could not be completed. |
GET
/api/v1/statsRequires API key
Retrieve public opportunity catalogue statistics.
Returns aggregate counts for approved public opportunities without exposing unpublished or suppressed records.
Parameters
This operation takes no parameters.
Responses
| Status | Body | Description |
|---|---|---|
| 200 | OpportunityStatsResponse | A public opportunity catalogue statistics snapshot. |
| 401 | ApiError | The request carried no valid API key. |
| 429 | ApiError | The client exceeded the rate limit for this endpoint. |
| 500 | ApiError | The request could not be completed. |
GET
/api/v1/opportunities/{id}Requires API key
Retrieve a single publicly listed opportunity.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes | Opportunity identifier. |
Responses
| Status | Body | Description |
|---|---|---|
| 200 | OpportunityResponse | The requested opportunity. |
| 400 | ApiError | The identifier is not a valid UUID. |
| 401 | ApiError | The request carried no valid API key. |
| 404 | ApiError | No publicly listed opportunity matches the identifier. |
| 429 | ApiError | The client exceeded the rate limit for this endpoint. |
| 500 | ApiError | The request could not be completed. |
Schemas
PublicOpportunity
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| id | string (uuid) | Yes | Stable opportunity identifier. |
| type | job | study | training | tender | other | Yes | Opportunity category. |
| title | string | Yes | Opportunity title as published by the source. |
| description | string | Yes | Full opportunity description. |
| organisationName | string | null | Yes | Publishing organisation name. |
| location | string | null | Yes | Location as published by the source. |
| deadline | string (date-time) | null | Yes | Application deadline. Null when the source published no deadline. |
| status | string | Yes | Publication state. Only approved opportunities are returned by this API. |
| tags | string[] | Yes | Free-form tags attached to the opportunity. |
| salaryRange | number[] | Yes | Lower and upper salary bounds in ZAR when the source published them. |
| createdAt | string (date-time) | null | Yes | Instant the opportunity entered the catalogue. |
| details | JobOpportunityDetails | StudyOpportunityDetails | TrainingOpportunityDetails | TenderOpportunityDetails | null | Yes | Category specific attributes. Null when the category carries no extra attributes. |
JobOpportunityDetails
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| salary | number | null | Yes | — |
| employmentType | string | null | Yes | — |
| experienceLevel | string | null | Yes | — |
| skills | string[] | Yes | — |
| sector | string | null | Yes | — |
| category | string | null | Yes | — |
StudyOpportunityDetails
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| institution | string | null | Yes | — |
| programme | string | null | Yes | — |
| programmeLevel | string | null | Yes | — |
| fundingAmount | number | null | Yes | — |
| requirements | string | null | Yes | — |
TrainingOpportunityDetails
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| duration | number | null | Yes | — |
| format | string | null | Yes | — |
| prerequisites | string | null | Yes | — |
| price | number | null | Yes | — |
TenderOpportunityDetails
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| tenderNo | string | null | Yes | — |
| category | string | null | Yes | — |
| tenderType | string | null | Yes | — |
| organOfState | string | null | Yes | — |
| province | string | null | Yes | — |
| closingDate | string (date-time) | null | Yes | — |
| listingUrl | string | null | Yes | — |
Pagination
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| page | integer | Yes | One-based index of the returned page. |
| pageSize | integer | Yes | Number of records requested per page. |
| total | integer | Yes | Total number of matching opportunities. |
| totalPages | integer | Yes | Total number of pages available for this query. |
| hasNextPage | boolean | Yes | True when a further page of results exists. |
OpportunityListResponse
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| data | PublicOpportunity[] | Yes | — |
| pagination | Pagination | Yes | — |
OpportunityResponse
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| data | PublicOpportunity | Yes | — |
OpportunityStats
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| total | integer | Yes | Total number of approved public opportunities. |
| byType | object | Yes | Approved public opportunity counts keyed by opportunity category. |
| nextDeadline | string (date-time) | null | Yes | Soonest upcoming public opportunity deadline. Null when none is known. |
| generatedAt | string (date-time) | Yes | Instant the statistics snapshot was generated. |
OpportunityStatsResponse
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| data | OpportunityStats | Yes | — |
ApiErrorDetail
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| path | string | Yes | Dotted path of the offending field. |
| message | string | Yes | Human readable explanation of the failure. |
ApiError
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| error | object | Yes | — |
FastApiValidationIssue
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | — |
| loc | string | number[] | Yes | — |
| msg | string | Yes | — |
| input | unknown | No | — |
| ctx | object | No | — |
FastApiValidationError
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| detail | FastApiValidationIssue[] | Yes | — |