Integrate with Chance AI
Developer portal
Chance AI Public API
v1.0.0
Search and retrieve publicly listed opportunities. An [MCP server](/developers/mcp) exposes the same catalogue to AI agents.
https://api.chance.africaAuthentication
Send your API key as a bearer token: Authorization: Bearer ca_live_…
Read endpoints also accept anonymous requests, but those are limited per IP address and do not draw down your monthly allowance.
Endpoints
GET
/api/v1/opportunitiesSearch 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. |
| 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. |
| 400 | ApiError | The query string failed validation. |
| 429 | ApiError | The client exceeded the rate limit for this endpoint. |
| 500 | ApiError | The request could not be completed. |
POST
/api/v1/opportunitiesRequires API key
Submit an opportunity for review.
Reserved for a future release. The endpoint currently responds with 501 Not Implemented.
Parameters
This operation takes no parameters.
Request body
application/json encoded as OpportunitySubmission
Responses
| Status | Body | Description |
|---|---|---|
| 202 | OpportunitySubmissionAccepted | The submission was accepted and queued for review. |
| 400 | ApiError | The submission failed validation. |
| 401 | ApiError | The request carried no valid API credential. |
| 429 | ApiError | The client exceeded the rate limit for this endpoint. |
| 501 | ApiError | Submissions are not accepted yet. |
GET
/api/v1/jobsSearch 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. |
| 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. |
| 400 | ApiError | 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/opportunities/{id}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. |
| 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. |
GET
/api/v1/openapi.jsonRetrieve this OpenAPI document.
Parameters
This operation takes no parameters.
Responses
| Status | Body | Description |
|---|---|---|
| 200 | object | The OpenAPI description of the public API. |
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 | — |
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 | — |
OpportunitySubmission
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| type | job | study | training | tender | other | Yes | Opportunity category. |
| title | stringmin length 3 · max length 300 | Yes | Opportunity title. |
| description | stringmin length 20 · max length 20000 | Yes | Full opportunity description. |
| organisationName | stringmax length 200 | No | Publishing organisation name. |
| location | stringmax length 200 | No | Location for the opportunity. |
| deadline | string (date-time) | No | Application deadline. |
| applicationUrl | string (uri) | No | Canonical link to the original listing. |
| tags | string[]max items 20 | No | Free-form tags. |
OpportunitySubmissionAccepted
Type: object
| Field | Type | Required | Description |
|---|---|---|---|
| id | string (uuid) | Yes | Identifier assigned to the submitted opportunity. |
| status | string | Yes | Submissions are created as pending and stay private until a reviewer approves them. |