Skip to main content

Employment Equity Plans

An Employment Equity (EE) Plan is a multi-year plan that captures the demographic workforce targets an organisation commits to. A plan is scoped to an account and is split into one milestone per financial year (September 1 – August 31). Each milestone holds two targets: one for all employees and one for employees with disabilities. A target records roughly 100 counters — one per race × gender × occupational level combination.

The API lets you:

  • Create a new plan (optionally pre-filled with the current workforce demographics from a scorecard).
  • Retrieve plans with their nested milestones and targets.
  • Update plan-level metadata.
  • Update individual target values on a specific milestone.
  • Delete a plan (milestones and targets are cascaded).

Endpoints

MethodPathPurpose
GET/api/public/v1/employment_equity_plansList all plans on the account
GET/api/public/v1/employment_equity_plans/{plan_id}Retrieve a single plan with nested milestones and targets
POST/api/public/v1/employment_equity_plansCreate a new plan (optionally with baseline prefill)
PATCH/api/public/v1/employment_equity_plans/{plan_id}Update plan metadata
DELETE/api/public/v1/employment_equity_plans/{plan_id}Delete a plan and its milestones/targets
PATCH/api/public/v1/employment_equity_plans/{plan_id}/employment_equity_milestones/{milestone_id}/employment_equity_targets/{target_id}Update the demographic counters on a single target
Authentication

Include the following headers on every request:

  • Authorization: HMAC <signature>
  • X-Api-Key: <your account key>
  • Accept: application/json

See Authentication.


Attributes

Plan

FieldTypeRequiredDescription
namestringnoHuman-readable plan name. If blank, the API derives a description from the plan dates.
start_datestringyesPlan start date (YYYY-MM-DD). Must be on or after 2025-09-01.
end_datestringyes on createPlan end date (YYYY-MM-DD). For post-2025 plans this is automatically clamped to 2030-08-31.
scorecard_idstring | nullnoId of an optional scorecard on the same account (e.g. scorecard_Y2EQKp8z1r9jeToPW6deGwo9), matching the identifier exposed by the Scorecards API. When supplied on create, the API pre-fills every target's counters using that scorecard's current workforce demographics. Supplying it on update only rebinds the scorecard reference — it does not re-run the prefill.
sectorstring | nullnoThe published industry sector whose sectoral EE targets this plan benchmarks against (e.g. "Construction", "Financial and Insurance Activities"). The plan's sector — when set — is the source of truth for sectoral-target lookups across every scorecard linked to the plan. If left blank, lookups fall back to each individual scorecard's own per-scorecard sector setting. See Sector values below for the accepted strings.

Milestone (response only)

FieldTypeDescription
idintegerMilestone ID (used in the target update path).
year_numberinteger1-indexed year number of the plan (1 = first year).
start_datestringISO date for the start of the financial year.
end_datestringISO date for the end of the financial year.

Target

FieldTypeDescription
idintegerTarget ID (used in the target update path).
target_typestringOne of all_employees, disabled_employees. Immutable.
number_of_{race}_{gender}_{occupational_level}integerA non-negative count per demographic slice. See Counter fields for the complete list.

System fields (response only)

FieldTypeDescription
idintegerPlan ID.
erastringEither pre_2025 or post_2025. Plans created through this API default to post_2025.
created_atdatetimeCreation timestamp.
updated_atdatetimeLast update timestamp.

Enumerations

target_type

  • all_employees
  • disabled_employees

era

  • pre_2025
  • post_2025

Sector values

sector accepts any of the following strings (case-sensitive). These are the same industry sectors used by the BEEtoolkit sectoral-target tables:

  • Accommodation and Food Service Activities
  • Administrative and Support Activities
  • Agriculture, Forestry & Fishing
  • Arts, Entertainment and Recreation
  • Construction
  • Education
  • Electricity, Gas Steam and Air Conditioning Supply
  • Financial and Insurance Activities
  • Human Health and Social Work
  • Information and Communication
  • Manufacturing
  • Mining and Quarrying
  • Professional Scientific and Technical
  • Public Administration and Defence; Compulsory Social Security
  • Real Estate Activities
  • Transport and Storage
  • Water Supply, Sewerage, Waste Management and Remediation Activities
  • Wholesale and Retail Trade; Repair of Motor Vehicles and Motorcycles

Any other value returns 422 with an inclusion error. Leaving sector blank/null is allowed — sectoral-target lookups then fall back to each linked scorecard's own per-scorecard sector setting.

Counter fields

Each target exposes one integer counter per number_of_{race}_{gender}_{occupational_level} combination.

  • Races: african, coloured, indian, white, foreign
  • Genders: male, female
  • Occupational levels: top_managers, senior_managers, middle_managers, junior_managers, semi_skilled_employees, unskilled_employees, plus a handful of temporary / permanent slices

See the target response below for the full rendered field list.


Notes

  • All dates use ISO 8601 (YYYY-MM-DD) in both requests and responses.
  • start_date must be on or after 2025-09-01.
  • Plans on post_2025 era have end_date automatically clamped to 2030-08-31.
  • Baseline prefill is a create-time convenience. If you need to reload baselines later, delete the plan and re-create it.
  • A target's target_type cannot be changed; attempting to set it is silently ignored.
  • Counter fields must be non-negative integers. Negative values return 422.
  • Deleting a plan cascades to its milestones and all their targets.
  • In the Retrieve a plan response, milestones are ordered by year_number ascending and targets are ordered with all_employees before disabled_employees. The list endpoint omits milestones and targets entirely.

List plans

Retrieve all plans on the account. This endpoint returns plan metadata only — use Retrieve a plan for the full nested milestones and targets.

GET /api/public/v1/employment_equity_plans

Code examples

curl -X GET "https://www.beetoolkit.co.za/api/public/v1/employment_equity_plans" \
-H "Accept: application/json" \
-H "X-Api-Key: <your account key>" \
-H "Authorization: HMAC <your signature>"

Response

[
{
"id": 42,
"name": "FY26 EE Plan",
"start_date": "2025-09-01",
"end_date": "2030-08-31",
"era": "post_2025",
"scorecard_id": "scorecard_Y2EQKp8z1r9jeToPW6deGwo9",
"sector": "Construction",
"created_at": "2026-04-22T08:30:00.000Z",
"updated_at": "2026-04-22T08:30:00.000Z"
}
]

Retrieve a plan

Retrieve a single plan with its milestones and targets.

GET /api/public/v1/employment_equity_plans/{plan_id}

Path parameters

NameTypeRequiredDescription
plan_idintegeryesThe plan identifier.

Code examples

curl -X GET "https://www.beetoolkit.co.za/api/public/v1/employment_equity_plans/{plan_id}" \
-H "Accept: application/json" \
-H "X-Api-Key: <your account key>" \
-H "Authorization: HMAC <your signature>"

Response

{
"id": 42,
"name": "FY26 EE Plan",
"start_date": "2025-09-01",
"end_date": "2030-08-31",
"era": "post_2025",
"scorecard_id": "scorecard_Y2EQKp8z1r9jeToPW6deGwo9",
"sector": "Construction",
"created_at": "2026-04-22T08:30:00.000Z",
"updated_at": "2026-04-22T08:30:00.000Z",
"milestones": [
{
"id": 101,
"year_number": 1,
"start_date": "2025-09-01",
"end_date": "2026-08-31",
"targets": [
{
"id": 201,
"target_type": "all_employees",
"number_of_african_male_top_managers": 0,
"number_of_coloured_male_top_managers": 0,
"number_of_indian_male_top_managers": 0,
"number_of_white_male_top_managers": 0,
"number_of_african_female_top_managers": 0,
"number_of_coloured_female_top_managers": 0,
"number_of_indian_female_top_managers": 0,
"number_of_white_female_top_managers": 0,
"number_of_foreign_male_top_managers": 0,
"number_of_foreign_female_top_managers": 0,
"number_of_african_male_senior_managers": 0,
"number_of_coloured_male_senior_managers": 0
/* …additional counters for middle/junior/semi_skilled/unskilled levels… */
},
{
"id": 202,
"target_type": "disabled_employees",
"number_of_african_male_top_managers": 0
/* …same counter set as above… */
}
]
}
/* …milestones 2 through N… */
]
}

Create a plan

Create a new EE plan with milestones and empty targets. If a scorecard_id from the same account is supplied, every target is pre-filled with that scorecard's current workforce demographics ("baseline prefill").

POST /api/public/v1/employment_equity_plans

Request body

{
"employment_equity_plan": {
"name": "FY26 EE Plan",
"start_date": "2025-09-01",
"end_date": "2030-08-31",
"scorecard_id": "scorecard_Y2EQKp8z1r9jeToPW6deGwo9",
"sector": "Construction"
}
}
Empty vs. baseline-prefilled

Omit scorecard_id to create a plan with zero-valued targets that you'll populate later via the target update endpoint. Supply scorecard_id to have each target's counters pre-filled from the current workforce on that scorecard.

Code examples

curl -X POST "https://www.beetoolkit.co.za/api/public/v1/employment_equity_plans" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Api-Key: <your account key>" \
-H "Authorization: HMAC <your signature>" \
-d '{
"employment_equity_plan": {
"name": "FY26 EE Plan",
"start_date": "2025-09-01",
"end_date": "2030-08-31",
"scorecard_id": "scorecard_Y2EQKp8z1r9jeToPW6deGwo9",
"sector": "Construction"
}
}'

Response

Returns 201 Created with the full plan (milestones and targets included), using the same shape as Retrieve a plan.

Errors

StatusDescription
422Validation failed — e.g. start_date is before 2025-09-01, or scorecard_id does not resolve to a scorecard visible to the caller.
{
"errors": [
"Start date cannot be before 01/09/2025"
]
}

A 422 with Scorecard not found is returned when scorecard_id is unknown to the caller. The response does not distinguish between a non-existent id and one belonging to a different account.


Update a plan

Update plan-level metadata. Only name, scorecard_id, and sector are editable — see Editable fields below. Target values are not editable through this endpoint; use the target update endpoint instead.

PATCH /api/public/v1/employment_equity_plans/{plan_id}

Path parameters

NameTypeRequiredDescription
plan_idintegeryesThe plan identifier.

Editable fields

FieldEditable on update?Notes
nameyesFree-text; no validation beyond length.
scorecard_idyesAccepts the scorecard id. Rebinding only updates the reference — it does not re-run the baseline prefill across existing targets.
sectoryesMust be one of the sector values or null. Changing sector only affects sectoral-target lookups going forward; it does not retroactively rewrite stored target counters.
start_date, end_datenoIgnored on update. Plan dates drive milestone generation and are fixed at create time; if you need different dates, delete the plan and create a new one.

Request body

{
"employment_equity_plan": {
"name": "Updated plan name",
"scorecard_id": "scorecard_Y2EQKp8z1r9jeToPW6deGwo9",
"sector": "Construction"
}
}

Code examples

curl -X PATCH "https://www.beetoolkit.co.za/api/public/v1/employment_equity_plans/{plan_id}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Api-Key: <your account key>" \
-H "Authorization: HMAC <your signature>" \
-d '{
"employment_equity_plan": {
"name": "Updated plan name"
}
}'

Response

Returns 200 OK with the updated plan, including nested milestones and targets.

Errors

StatusDescription
404The plan does not exist on the account.
422Validation failed — e.g. invalid start_date, or scorecard_id does not resolve to a scorecard visible to the caller.

Delete a plan

Delete a plan and all its milestones and targets.

DELETE /api/public/v1/employment_equity_plans/{plan_id}

Path parameters

NameTypeRequiredDescription
plan_idintegeryesThe plan identifier.

Code examples

curl -X DELETE "https://www.beetoolkit.co.za/api/public/v1/employment_equity_plans/{plan_id}" \
-H "Accept: application/json" \
-H "X-Api-Key: <your account key>" \
-H "Authorization: HMAC <your signature>"

Response

Returns 204 No Content on success.

Errors

StatusDescription
404The plan does not exist on the account.

Update a target

Update one or more demographic counters on a single target. target_type cannot be changed; unrecognised fields are ignored.

PATCH /api/public/v1/employment_equity_plans/{plan_id}/employment_equity_milestones/{milestone_id}/employment_equity_targets/{target_id}

Path parameters

NameTypeRequiredDescription
plan_idintegeryesThe plan identifier.
milestone_idintegeryesThe milestone identifier (from the nested plan response).
target_idintegeryesThe target identifier (from the nested milestone response).

Request body

Only send the counters you want to update — all other counters are left untouched.

{
"employment_equity_target": {
"number_of_african_male_top_managers": 3,
"number_of_coloured_female_senior_managers": 1
}
}

Code examples

curl -X PATCH "https://www.beetoolkit.co.za/api/public/v1/employment_equity_plans/{plan_id}/employment_equity_milestones/{milestone_id}/employment_equity_targets/{target_id}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Api-Key: <your account key>" \
-H "Authorization: HMAC <your signature>" \
-d '{
"employment_equity_target": {
"number_of_african_male_top_managers": 3
}
}'

Response

Returns 200 OK with the updated target:

{
"id": 201,
"target_type": "all_employees",
"number_of_african_male_top_managers": 3,
"number_of_coloured_female_senior_managers": 1
/* …remaining counters unchanged… */
}

Errors

StatusDescription
404The plan, milestone, or target is not accessible to the account.
422One or more counter values are invalid (e.g. negative).