ADAM

API Access to ADAM

Introduction the ADAM API

An API allows for another computer program to connect to ADAM to either access data stored in its database or to make changes to that data. ADAM makes use of a “RESTful” API and returns data mostly in JSON format.

What is a RESTful system?

REST is a technique of communicating with an API which is very common amongst web-based applications - such as ADAM. Other programs will make one of four types of web request depending on what they are hoping to do in the database, and include the necessary information for ADAM. ADAM then responds to that request with the appropriate data or success code.

How does access control work?

Access to the ADAM database is controlled using a token system. These are essentially random passwords that are created which are shared only with the other program that wishes to access the API. Because these tokens are really only meant to be used by a computer, it is not important that they are memorable or easy to type. In fact, ADAM will generate a random set of characters to be used as the API key and you are strongly encouraged to make use of the suggested token.

Warning

It is vitally important that the token is kept confidential between the person issuing it and the person using it. Anyone who knows the token will be able to access the API. Please read the Best Practices section below for further information.

Each API token can be given access to one or more API resources. Anyone who knows the API token can access all the resources that have been allocated to that token.

API tokens can be revoked at any point and can have their resources changed and added to over time. A token can also be suspended — temporarily blocked without deleting it — and later reactivated. Any changes you make to the token and its API resource assignments will take place immediately.

Managing API Tokens in ADAM

In ADAM: Navigate to Administration → Security Administration → Manage API Tokens.

A list of existing API tokens will be shown. Click on Add new API Token to begin the process of creating a new Token.

  1. A random 30-character token will be generated. This should be left unmodified unless you have a very specific reason to do so. Once set, token values cannot be changed. If you need to change the token, you must delete the existing endpoint and create a new one.
  2. Select the appropriate resources to allow the token to access. Hold down the “Ctrl” key on your keyboard to allow you to select multiple resources by then clicking on those resources while holding down that button.
  3. Add notes if required. It is a good idea to make note of what service is making use of the API token.
  4. Click on Save Token.

Warning

The random 30 character token must be kept secret since it will allow anyone who knows it access to the data stored in the ADAM database. It will need to be shared with the integration provider and great care should be taken with how they are provided the API key. We strongly recommend against sending this information via email or other unsecured means.

Managing Existing Tokens

In the table of existing API tokens, each row has a Status column and an Actions column. The Status column shows whether the token is currently Active or Suspended. In the Actions column you have the option to edit, delete, regenerate, and — depending on the current status — suspend or reactivate the API token.

Edit allows you to change the Resources and Notes associated with an endpoint, but does not allow you to edit the Token.

Regenerating a token will create a new random value for the token but will keep your resources and notes the same. If you do regenerate a token, please remember to update your external systems with the new token.

Deleting the token will remove it from the list and it will no longer be available for use. Systems that rely on the resources will no longer have access to the data supplied by ADAM.

Suspending and Reactivating Tokens

Suspending a token is a reversible alternative to deleting it. A suspended token is kept in the list, together with all its resources and notes, but is rejected by the API until it is reactivated. This is useful when you need to stop a service from accessing ADAM temporarily — for example while you investigate unexpected activity — without losing the token and having to reconfigure the external system with a new one later.

To suspend an active token, click suspend in the Actions column of that token’s row. You will be asked to confirm with the message “Suspend API token? This immediately blocks all requests using this token.” Once confirmed, the token’s Status changes to Suspended and ADAM shows the message “The API token has been suspended.”

A suspended token is clearly marked in the list, and its Actions column offers reactivate in place of suspend.

To bring a suspended token back into use, click reactivate in the Actions column of that token’s row. Its Status returns to Active and ADAM shows the message “The API token has been reactivated.”

Note

Suspending and reactivating a token both take effect immediately. Because the token value itself is unchanged, you do not need to update your external systems when you reactivate a token — it simply starts working again.

Warning

While a token is suspended, any request that uses it is refused as though the token had no access to the resource, and the calling system receives a “403 Forbidden” response. Make sure the service that relies on the token is prepared to handle being blocked before you suspend it.

The difference between the two ways of stopping a token is important:

  • Suspend is temporary and fully reversible. The token, its resources and its notes are all kept, and access can be restored at any time by reactivating it.
  • Delete is permanent and cannot be undone. The token is removed from the list entirely and cannot be recovered; a new token would have to be created and shared with the external system.

Best Practice Security Principals

The following are provided as best practice guidelines for managing API tokens.

  1. Treat API Tokens as top secret. Do not send them via email and do not publish them in a place where they could be accessed by unauthorised personnel. API access can expose sensitive data. Allowing an API token to fall into the wrong hands could expose personal information about the users of your system and this would be considered an offence under the “Protection of Personal Information Act” (POPIA). Access to such personal information could become a security and safety issue.
  2. Each entity (e.g. a program that is accessing data from ADAM) should have its own token or tokens. Tokens should never be shared between entities. If another entity requires access to the same data, give it a new token. This allows you to revoke each token individually and stop one program from accessing the data without affecting any other programs.
  3. Programmers integrating with the ADAM API should not, under any circumstances, include API tokens in their source code and should always fetch them from some form of access controlled data storage.

API Interactions

Authentication

All API requests should be authenticated using a Bearer Token.

Example:

Authenticating with the token value svyzBvkuuXLdJwV7YcdYsQFVX5ha54 would yield the following header:

Authorize: Bearer svyzBvkuuXLdJwV7YcdYsQFVX5ha54

ADAM also will accept a Basic Authorization header with an arbitrary username. Authenticating with the username apitoken token value svyzBvkuuXLdJwV7YcdYsQFVX5ha54 would yield the following header:

Authorize: Basic YXBpdG9rZW46c3Z5ekJ2a3V1WExkSndWN1ljZFlzUUZWWDVoYTU0

API Requests

All API requests, as listed below, should be prefixed with the “api” folder to make the URL end-point:

https://*adam.example.com*/api/

The remainder of the URL generally consists of a module name, a data set and zero or more parameters. These should all be in lower-case. For example:

https://demo.adam.co.za/api/request/test/parameter

Parameters should be “percent encoded”. Spaces should be encoded as %20 and not as a “+”.

A GET request to this API end-point would require token access to the resource: request/test:get. Note that without specifically assigned access, access to the resource - even this test resource - will be denied.

API Responses

All responses will be returned within JSON objects. The basic structure of these objects is:

{
  "data": null,
  "message": "",
  "response": {
    "error": "",
    "code": 200
  }
}

Any response which does not have these properties as listed above, MUST be treated as invalid.

The contents of the data attribute will depend on the API endpoint being interrogated.

The message attribute contains a human-readable message which, in most cases, describes the data set that has been returned. This is intended for debugging and may change unpredictably with future versions of ADAM.

The response code should mirror the HTTP response code which will be descriptive of the success or failure of the call. The error attribute will provide a human-readable description of the error. The error message is not intended to be interpreted by machines.

API Resources

These are the available documented resources. Other resources are available but are not listed here until their development is complete and considered stable.

AbsenteeKiosk/register:post

This registers a pupil as either present or late. It is intended to be used either by automated access control systems or ADAM’s own absentee kiosk.

Request

  • POST to /api/absenteekiosk/register/<pupil>
  • POST to /api/absenteekiosk/register with pupil=<pupil> as a form variable in the POST body

Parameters

  • <pupil>: The ADAM identifier of the pupil.

Response

If the pupil identifier can be matched against an existing pupil, the endpoint will return two items in the data object. These are used internally by ADAM’s “Absentee Kiosk” feature.

  • message: an HTML message which will contain the name of the pupil and confirmation that they have been registered.
  • colour: an HTML hex code either red, green or amber depending on the status.

The times and windows are configured in ADAM’s site settings. Depending on these settings, ADAM will report one of the following HTTP status codes:

  • The pupil identifier is not recognised: 404 (Not found)
  • The pupil is too early and registers before the earliest time allowed: 406 (Not acceptable)
  • The pupil registers during the first window and is recorded as present: 200 (OK)
  • The pupil registers during the second window and is recorded as late: 202 (Accepted)
  • The pupil is too late and registers after the second window closes: 406 (Not acceptable)

In each case, the status code will be corroborated by a more descriptive message.

Example:

{
  "data": {
    "message": "<strong>Joe Smith</strong> has been recorded as <strong>present</strong>",
    "colour": "green"
  },
  "message": "",
  "response": {
    "error": "Present",
    "code": 200
  }
}

Absentees/summarycount:get

Returns a list of pupils and the number of days they’ve been absent. This counts all the absentees with a reason that is set to count as “absent”. Only pupils with absentee records are returned. All pupils, including those that might have left the school, are returned.

Request

GET /api/absentees/summarycount/<from>[/<to>]

Parameters

  • <from>: An ISO formatted date to begin the summary. This date is included in the summary.
  • <to>: OPTIONAL. An ISO formatted date to mark the end of the range of the summary. This date is included in the summary. If omitted, the current date is used instead.

Response

The data attribute will be an array of zero or more JSON objects.

Example:

GET /api/absentees/summarycount/2018-01-01/2018-01-31
{
  "data": [
    {
      "pupil_id": 875,
      "pupil_admin": "19634",
      "absent_count": 1
    },
    {
      "pupil_id": 879,
      "pupil_admin": "52351",
      "absent_count": 2
    }
  ],
  "message": "Absentee counts for all pupils from 2018-01-01 to 2018-01-31.",
  "response": {
    "error": "OK",
    "code": 200
  }
}
  • pupil_id is ADAM’s internal database identifier and will always refer to a unique pupil.
  • pupil_admin is the user-defined administration number. While this should not change, it may do so at the school’s discretion.
  • absentee_count is the number of days that the pupil has been recorded as absent. This does not include absentee records which do not prejudice a pupil (such as “away on sports tour”). These reasons are customisable by the school.

Absentees/list:get

Gets a list of pupils absent with the reasons.

Request

GET /api/absentees/list/[<date>[/<to>]]

Parameters

  • <date>: OPTIONAL. An ISO formatted date to query the absentees. If omitted, today’s date is used.
  • <to>: OPTIONAL. An ISO formatted date. If provided, all absentees on or between the <date> and <to> dates will be provided. If omitted, <to> effectively takes the same value as <date> and only absentees for that date are provided.

Response

GET /api/absentees/list/2018-01-30
{
  "data": [
    {
      "pupil_id": 1720,
      "pupil_admin": "47547",
      "absent_date": "2018-01-31",
      "absent_reason_id": 1,
      "absent_reason_description": "Absent",
      "absent_notes": "App Test"
    }
  ],
  "message": "Absentee list for all pupils from 2018-01-31 to 2018-01-31.",
  "response": {
    "error": "OK",
    "code": 200
  }
}

The data attribute contains an array of zero or more absentee records. Each record is a JSON object with the following properties:

  • pupil_id is ADAM’s internal identifier for the pupil.
  • pupil_admin is a school-provided identifier for the pupil. While this should not change, it may do so at the school’s discretion.
  • absent_date gives the date that the absentee occurred on in case a range of dates was requested. A pupil can only have a single absentee record per day.
  • absent_reason is an internal identifier corresponding to the absentee reason that was chosen.
  • absent_reason_description is the descriptor for the absentee reason. It will be consistent per absent_reason in any one API call, but may change between calls at the school’s discretion.
  • absent_notes contain the end-user provided notes related to the pupil’s absence. This may contain personal information.

Absentees/daysabsentforpupil:get

Returns the absentee log for a specific pupil.

Request

GET /api/absentees/daysabsentforpupil/<pupil>/<year>

Parameters

  • <pupil>: ADAM internal pupil identifier (required)
  • <year>: Calendar year to filter by (optional; returns all records if omitted)

Response

Data attribute contains the pupil’s absentee log entries.

Admin/test:get

Internal test endpoint for verifying API connectivity.

Request

GET /api/admin/test

Parameters

None.

Response

{
  "data": "Successfully fetched data by asynchronous call from the server at 2026-04-09 14:30:00",
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

Applications/applicationformfields:get

The ability to see which fields are accepted as part of the application form. These fields can be customised by updating the core and custom fields to change their availability in the application form.

Request

GET /api/applications/applicationformfields

Parameters

None

Response

The output data will be a JSON object containing the fields that are accepted. Within the data property are two sub arrays for families and pupils. These list the field names that are accepted.

Example:

GET https://demo.adam.co.za/api/applications/applicationformfields
{
  "data": {
    "families": [
      "family_primary_idnum",
      "family_primary_lastname",
      "family_primary_firstname",
      "family_primary_fullfirst",
      "family_primary_title",
      "family_primary_initials",
      "family_primary_gender",
      "family_primary_birth",
      "family_primary_occupation",
      "family_primary_employer",
      "family_primary_workphone",
      "family_primary_cell",
      "family_primary_cell_sms",
      "family_primary_email",
      "family_secondary_idnum",
      "family_secondary_lastname",
      "family_secondary_firstname",
      "family_secondary_fullfirst",
      "family_secondary_title",
      "family_secondary_initials",
      "family_secondary_gender",
      "family_secondary_birth",
      "family_secondary_occupation",
      "family_secondary_employer",
      "family_secondary_workphone",
      "family_secondary_cell",
      "family_secondary_cell_sms",
      "family_secondary_email",
      "family_address_residential_1",
      "family_address_residential_2",
      "family_address_residential_suburb",
      "family_address_residential_city",
      "family_address_residential_province",
      "family_address_residential_code",
      "family_address_residential_country",
      "family_address_postal_1",
      "family_address_postal_2",
      "family_address_postal_suburb",
      "family_address_postal_city",
      "family_address_postal_province",
      "family_address_postal_code",
      "family_address_postal_country",
      "family_home_phone",
      "family_home_fax",
      "family_ice",
      "family_ice_number",
      "family_report_required"
    ],
    "pupils": [
      "pupil_lastname",
      "pupil_fullfirst",
      "pupil_firstname",
      "pupil_gender",
      "pupil_idnumber",
      "pupil_birth",
      "pupil_religion",
      "pupil_population_id",
      "pupil_language_id",
      "pupil_language_other",
      "pupil_teaching_language_id",
      "pupil_entry",
      "pupil_final",
      "pupil_email",
      "pupil_cell",
      "pupil_cell_sms",
      "pupil_allergies",
      "pupil_medaid_name",
      "pupil_medaid_number",
      "pupil_medaid_principal",
      "pupil_medaid_principal_id",
      "pupil_doctor",
      "pupil_doctor_phone",
      "pupil_orphan_status",
      "pupil_relationships",
      "pupil_atschool",
      "pupil_prevschool_firstprovince",
      "pupil_prepschool",
      "pupil_prevschool_country",
      "pupil_prevschool_formalgrr",
      "pupil_nationality",
      "pupil_studypermit_required",
      "pupil_studypermit",
      "custom_38",
      "custom_36"
    ]
  },
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

Applications/apply:post

Submit an application to the site. Note that if the ID number submitted matches an existing parent, the child will automatically be linked to that parent. Note that when applications are submitted through ADAM’s web interface, ADAM automatically authenticates the parent to ensure that strange children are not linked to their profiles. Implicit in the web application is the validation of the email address which is done as part of the application process. Applications received via the API are not given such scrutiny and special care should be taken on the sending system to mitigate against spam and fraudulent attempts at applications.

Request

POST /api/applications/apply

Parameters

None - data sent by message body.

Body

The body of the request should contain the data required for the application. The data should either be in JSON format, or as an encoded query string (as is typical with normal form-submitted data).

Fields: The three fields, idnumber, email, and phone, may be duplicated within the parent information. It is not necessary that they complete them twice, but it is necessary for the information to be submitted both with the family and as separate information.

Note carefully the point about existing parents: if their ID or passport numbers already exist in ADAM’s database, the family information provided in the application will be silently discarded in favour of information already in the database. Thus having updated contact information provided in the email and phone fields is important. The silent discarding is to ensure that malicious actors cannot update family information without their authorisation.

  • idnumber: The South African ID or passport number of the parent making the submission. This is used to match against other families. If omitted, no linking will take place. If this value matched the value of an existing family, the pupil will automatically be linked to that family and the information provided in the family info will be lost.
  • email: The email address to get in tough with the parents regarding the application.
  • phone: The phone number to get in touch with the parents regarding the application.
  • application: The body of the application. This contains:

    • pupil: An array of child information to be included on the application. Each element of the array is a sub-array of information for each child. A valid application must have at least one child and no more than 5 children.
    • family: An array of family fields to be included.
    • email: further details of the parents’ email addresses.

A minimum set of required fields is:

  • Families:

    • Primary last name (family_primary_lastname)
    • Primary first name (family_primary_firstname)
    • Primary full first names, can duplicate family_primary_firstname if required (family_primary_fullfirst)
  • Pupils:

    • Last name (pupil_lastname)
    • Preferred name (pupil_firstname)
    • Full first name, can duplicate pupil_firstname if required (pupil_fullfirst)
    • Gender (pupil_gender)
    • Year of entry (entry_year) - note non-standard field naming
    • Month of entry (entry_month) - note non-standard field naming
    • Grade of entry (entry_grade) - note non-standard field naming. Note, integers accepted only. For grades prior to Grade 1, zero or negative grades: Grade R = 0, Grade RR = -1, Grade RRR = -2, etc.
Example (JSON):
{
  "idnumber": "1234567890123",
  "email": "morticia@adam.co.za",
  "phone": "0834699569",
  "application": {
    "pupil": [
      {
        "pupil_lastname": "Addams",
        "pupil_firstname": "Wednesday",
        "pupil_fullfirst": "Wednesday Jane",
        "pupil_gender": "Female",
        "entry_year": "2019",
        "entry_month": "1",
        "entry_grade": "10",
        "relationship": [
          {
            "primary": "biological",
            "secondary": "step parent"
          }
        ]
      },
      {
        "pupil_lastname": "Addams",
        "pupil_firstname": "Pugsley",
        "pupil_fullfirst": "Pugsley Georgie",
        "pupil_gender": "Male",
        "entry_year": "2019",
        "entry_month": "1",
        "entry_grade": "8",
        "relationship": [
          {
            "primary": "step parent",
            "secondary": "biological"
          }
        ]
      }
    ],
    "family": {
      "family_primary_idnum": "1234567890123",
      "family_primary_lastname": "Addams",
      "family_primary_firstname": "Gomez",
      "family_primary_fullfirst": "Gomez",
      "family_secondary_idnum": "1234567890123",
      "family_secondary_lastname": "Addams",
      "family_secondary_firstname": "Morticia",
      "family_secondary_fullfirst": "Morticia May"
    },
    "email": [
      {
        "member": "primary",
        "address": "gomes@adam.co.za",
        "bulk": "Yes",
        "reports": "Yes"
      },
      {
        "member": "secondary",
        "address": "morticia@adam.co.za",
        "bulk": "Yes",
        "reports": "Yes"
      }
    ]
  }
}

Response

A simple object providing notification of success or failure. The application field gives a code unique to this application which will, in a future development, allow for editing of the application.

{
  "data": {
    "application": "6ESKmQYMWH3KbJUdAESsZUi3BysaLx"
  },
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

Applications/create:post

Creates a partially completed application and invites the parent to finish it themselves. This is intended for authoritative external systems — for example an application-fee payment provider — that already hold verified information about the parent and their children, and want that information to be carried into ADAM without the parent being able to contradict it.

The difference between this resource and Applications/apply:post is important:

  • Applications/apply:post submits a finished application. The application is completed immediately and appears in the list of applications awaiting approval.
  • Applications/create:post creates an application that is left open. The supplied information is stored as locked data, an email containing a continuation link is sent to the parent, and the parent then completes the rest of the application form in ADAM in the normal way. Only once the parent submits it does it appear for approval.

Locked information survives everything the parent does to the form, and is written authoritatively onto the family and pupil records when a member of staff approves the application.

Request

POST /api/applications/create

Parameters

None - data sent by message body.

Body

The body should either be in JSON format, or as an encoded query string (as is typical with normal form-submitted data).

  • email: The email address of the parent. The continuation link is sent to this address, so it must be a valid email address.
  • idnumber: The South African ID or passport number of the parent making the application. Any non-empty identifier is accepted, since parents may apply with a passport number. If this matches an existing family in ADAM, the application is linked to that family.
  • phone: The contact number for the parent.
  • children: The number of children on the application. A valid application must have at least one child and no more than 5 children. This determines how many sets of pupil details the parent is asked to complete.
  • locked: The information which the sending system is asserting. This contains:

    • family: An object of family field names and their values.
    • pupil: An array of objects of pupil field names and their values, one entry per child, numbered from zero. The array may be sparse: a child with nothing locked can be omitted or sent as {}.
    • readonly: The manifest of which of the locked fields the parent may not change.

      • family: A list of family field names.
      • pupil: An array, per child, of lists of pupil field names.

The field names accepted in the family and pupil objects are exactly those reported by Applications/applicationformfields:get.

Read-only and editable locked fields

A locked field listed in readonly is presented to the parent as a field they can see but cannot change. A locked field which is not listed in readonly is presented as an ordinary, editable field pre-filled with the supplied value — but the value supplied by the sending system is still the one written to ADAM when the application is approved. Use readonly where it would confuse a parent to be able to edit something (a payment reference, for example) and leave a field editable where the parent’s own correction is helpful to see but should not overrule the authoritative source.

Example (JSON):
{
  "email": "morticia@adam.co.za",
  "idnumber": "1234567890123",
  "phone": "0834699569",
  "children": 2,
  "locked": {
    "family": {
      "family_primary_idnum": "1234567890123",
      "family_primary_lastname": "Addams"
    },
    "pupil": [
      {
        "pupil_lastname": "Addams",
        "custom_38": "INV-00417"
      },
      {
        "custom_38": "INV-00418"
      }
    ],
    "readonly": {
      "family": [
        "family_primary_idnum"
      ],
      "pupil": [
        [
          "custom_38"
        ],
        [
          "custom_38"
        ]
      ]
    }
  }
}

Response

On success the data object contains two items:

  • application: A code unique to this application, for the sending system’s own record keeping. It is not a credential and cannot be used to open the application form.
  • continue_url: The same continuation link that has been emailed to the parent. A sending system can present this directly — as a “Continue your application” button after a payment, for instance — so that the parent does not have to wait for the email. The link expires after 7 days and may be used at most 20 times.
{
  "data": {
    "application": "6ESKmQYMWH3KbJUdAESsZUi3BysaLx",
    "continue_url": "https://demo.adam.co.za/api/click/dHrLPUuoSHi0tbAkNsX2NwYtoxlLPqIYr8ozfQxWCcIS7uzUEq"
  },
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

The continuation link is the only credential that opens the application, and it is exactly the secret contained in the parent’s email. It must be transmitted over HTTPS and must not be written to logs.

The email is sent whether or not the sending system uses continue_url.

Errors

Every failure is reported as 400 (Bad request) and nothing is created — there are no half-made applications to clean up. Where more than one thing is wrong, all of the messages are returned together in response.error.

  • Body of request not understood. — the body was empty or could not be read.
  • A valid email address is required.
  • A primary ID number is required.
  • Invalid number of children; cannot continue. — fewer than one, or more than five.
  • Unknown family fields: <list> / Unknown pupil fields (child <n>): <list> — a field name that is not accepted on the application form.
  • Locked pupil index out of range: <n> — locked information sent for a child beyond the number given in children.
  • Read-only family field has no value: <field> / Read-only pupil field has no value (child <n>): <field> — a field was named as read-only but no value was supplied for it.
  • Primary id number mismatch between idnumber and locked family_primary_idnum. — where family_primary_idnum is locked it must be identical to idnumber.

If the application cannot be written to the database, 500 (Internal server error) is returned with the error Unable to create application.

Existing families

If the ID number matches a family already in ADAM, the application is linked to that family and the parent is not asked to complete the family section again. In that case locked family fields are stored but are not written to the existing family record when the application is approved; this is the same protection that stops an application overwriting an existing family’s details. Locked pupil fields are applied as normal. Sending systems whose locked information is about the children — payment references and the like — are unaffected by this.

Applications/verifyid:get

Checks whether an ID number is associated with an existing family login account.

Request

GET /api/applications/verifyid/<idNumber>

Parameters

  • <idNumber>: South African ID number to look up (required)

Response

No data attribute. The response.message field indicates the result:

  • “authorization required” — ID number found and a password exists (family can log in)
  • “authorization not possible” — ID number found but no password set
  • “id number not found” (code 404) — no matching record

Assessment/recentresults:get

Returns recent assessment results for a pupil.

Request

GET /api/assessment/recentresults/<pupil>

Parameters

  • <pupil>: ADAM internal pupil identifier (required)

Response

Data attribute contains an array of assessment result objects:

{
  "data": [
    {
      "assessment_id": 42,
      "assessment_period_id": 3,
      "assessment_description": "Term 1 Test",
      "assessment_date": "2026-03-15",
      "assessment_releasedate": "2026-03-20",
      "assessment_total": 100,
      "assessment_weighting": 1.0,
      "assessment_weighting_display": "10%",
      "result_total": 78,
      "result_comment": "",
      "class_grade_id": 10,
      "class_description": "10A",
      "subject_name": "Mathematics",
      "subject_short": "Maths"
    }
  ]
}

Questions/questionbreakdown:get

Returns a per-question breakdown of a pupil’s assessment results.

Request

GET /api/questions/questionbreakdown/<pupil>/<assessment>

Parameters

  • <pupil>: ADAM internal pupil identifier (required)
  • <assessment>: Assessment identifier (required)

Response

Data attribute contains an array of question result objects:

{
  "data": [
    {
      "question_description": "Algebra",
      "outcome_name": "Patterns and Algebra",
      "answer_total": 8.5,
      "answer_level": "B",
      "question_total": 10
    }
  ]
}

Calendar/pupillinks:get

This provides calendar subscription links for all current pupils. API keys are generated automatically for pupils who don’t have one yet.

Request

GET /api/calendar/pupillinks/

Parameters

None required.

Response

GET /api/calendar/pupillinks/
{
    "data": [
        {
            "pupil_id": 142,
            "calendar_link": "webcal://adam.example.com/api/calendar/xK9mNp2qRs5tUv8wXy1zA4bCdEfGhIjKlMnOpQrStUvWxYz012"
        }
    ],
    "message": "",
    "response": {
        "error": false,
        "code": 200
    }
}

Calendar/stafflinks:get

This provides calendar subscription links for all current staff. API keys are generated automatically for staff who don’t have one yet.

Request

GET /api/calendar/stafflinks/

Parameters

None required.

Response

GET /api/calendar/stafflinks/
{
    "data": [
        {
            "staff_id": 3,
            "calendar_link": "webcal://adam.example.com/api/calendar/gMSrVY4iGLAdk3RDks7AK3a2BTFW9PAGgpt9MgPDvVd6vBS7im"
        }
    ],
    "message": "",
    "response": {
        "error": false,
        "code": 200
    }
}

Changelog/undo:post

Undoes a changelog entry, reverting a field to its previous value.

Request

POST /api/changelog/undo/<changeSet>

Parameters

  • <changeSet>: The changelog entry identifier (URL path parameter)

Response

  • Code 200: Undo successful
  • Code 403: Cannot undo the original entry (no previous value to restore)
  • Code 202: Undo operation failed

Classes/pupilteachers:get

This provides a list of classes that an individual pupil is registered for.

Request

GET /api/classes/pupilteachers/<pupil>

Parameters

  • <pupil> is the pupil identifier

Response

GET /api/classes/pupilteachers/123
{
    "data": [
        {
            "class_id": 1111,
            "class_description": "AB",
            "class_gradeyear": 10,
            "subject_name": "Geography",
            "subject_short": "Geo",
            "staff": {
                "staff_id": 321,
                "staff_lastname": "Van Der Walt",
                "staff_firstname": "Drikus",
                "staff_title": "Mr",
                "staff_email": "dvdwalt@school.example.com"
            },
            "teaching_assistants": [
                {
                    "staff_id": 1234,
                    "staff_lastname": "Smith",
                    "staff_firstname": "James",
                    "staff_title": "Mr",
                    "staff_email": "jsmith@school.example.com"
                }
            ],
            "class_friendly": "Geography Grade 10 AB"
        }
    ],
    "message": "",
    "response": {
        "error": "OK",
        "code": 200
    }
}

The data attribute contains one or more class objects. This contains the details of the subject, and the class.

Note that the class_gradeyear property can be negative to represent pre-school grades. (e.g. Grade 0 = Grade R, Grade -1 = Grade RR, and so on).

One staff member (the teacher of the class) will be provided, and the teaching_assistants may contain 0 or more staff objects.

Classes/bygradeperiodsubject:get

Returns classes matching a specific grade, reporting period, and subject combination.

Request

GET /api/classes/bygradeperiodsubject/<grade>/<period>/<subject>

Parameters

  • <grade>: Grade identifier (required)
  • <period>: Reporting period identifier (required)
  • <subject>: Subject identifier (required)

Response

{
    "data": [
        {
            "id": 150,
            "grade": 10,
            "gradetext": "Grade 10",
            "description": "10A",
            "subject": 5,
            "fulldescription": "Grade 10 Mathematics 10A",
            "teacher_id": 42,
            "teacher_name": "Mr Smith"
        }
    ]
}

Classes/list:get

Returns every current class in the school, with its subject, grade, teacher, teaching assistants, venue, category, and the number of pupils currently enrolled in it. This is the same set of classes shown by the List of All Classes report in ADAM.

Classes that have been deleted are not included.

Request

GET /api/classes/list

Parameters

This endpoint takes no parameters.

Response

{
    "data": [
        {
            "id": 42,
            "subject_id": 7,
            "subject": "Mathematics",
            "subject_short": "MAT",
            "description": "Maths 8A",
            "fulldescription": "Mathematics 8A (J Smith)",
            "grade": 8,
            "gradetext": "Grade 8",
            "grade_id": 4,
            "gradelevel": "Senior Phase",
            "teacher_id": 19,
            "teacher_name": "Mr J Smith",
            "teaching_assistants": [
                {
                    "id": 23,
                    "name": "Mrs A Bell"
                }
            ],
            "venue": "Room 12",
            "category_id": 1,
            "category": "Academic",
            "pupils": 27
        }
    ],
    "message": "",
    "response": {
        "error": "OK",
        "code": 200
    }
}

The data attribute contains one object per class, ordered as the List of All Classes report orders them — by category, then subject, then grade and class description.

teaching_assistants contains zero or more staff objects. pupils is the number of pupils currently enrolled, and matches the number of records returned by Classes/pupils:get for the same class.

Note that the grade property can be negative to represent pre-school grades (e.g. Grade 0 = Grade R, Grade -1 = Grade RR, and so on). It is null for a class that is not tied to a particular grade.

Classes/pupils:get

Returns the pupils who are currently enrolled in a particular class, together with the date on which each pupil’s registration in that class began.

Request

GET /api/classes/pupils/<class>

Parameters

  • <class>: The class identifier (URL path parameter, required). Class identifiers are returned by Classes/list:get.

Response

{
    "data": [
        {
            "id": 1183,
            "admin": "A2021-044",
            "firstname": "Thandi",
            "lastname": "Mokoena",
            "grade": 8,
            "datestart": "2026-01-12"
        }
    ],
    "message": "",
    "response": {
        "error": "OK",
        "code": 200
    }
}

The data attribute contains one object per pupil, ordered by surname and then first name. datestart is the date the pupil’s registration in this class began, in YYYY-MM-DD format.

The list reflects who is in the class today. A pupil appears only if their registration in the class covers today and they are still enrolled at the school — pupils who have left are not included, even if their class registration was never formally ended. For this reason the number of records returned always matches the pupils count given by Classes/list:get.

A class with nobody currently enrolled in it returns an empty data list with a 200 response code.

  • Code 200: The class exists; data contains the (possibly empty) list of pupils
  • Code 404: No such class, or the class has been deleted

Cron/cronlog:get

Returns cron job execution logs. Restricted to super-admin tokens.

Request

GET /api/cron/cronlog/<cronLogID>

Parameters

  • <cronLogID>: Either a numeric log entry ID (returns that specific record with full log content) or any non-numeric value (returns all records without log content)

Response

When requesting a specific entry, returns the full cron log record including log output. When requesting all entries, returns an array of records without the log body to reduce payload size.

DataQuery/get:get

Provides automated access to a whole-school scratch list. The contents of the scratch list fields can be customised as per the settings in ADAM found at Administration → Security → Manage Data Query API Fields.

Please treat this feature with the utmost care. By its very definition, it gives wide access to a range of personal data.

Create a Data Query Secret

To use this API endpoint, an additional data query token must be defined.

Note that field access definitions can only be linked to a single API Token. If multiple API tokens require access to the same fields, this process must be duplicated for each API token and a unique list created for each.

  • Select the API Token that you want to associate with this query. Note that only API Tokens who have access to the DataQuery/get/get resource may be selected here.
  • Make a note of the Secret and do not share this with unauthorised personnel.
  • Choose a data source for the query. Once set here, this cannot be changed later.
  • Add a comment to provide insight into the function and reason for this query.

Click on Add record when done.

A second screen will show, allowing you to select the fields required for this query:

Check the fields that you require and save your selections using the button at the bottom.

Request

GET /api/dataquery/get/<secret>

OR, for a modified data structure to provide more consistency for automated systems, (see example response below), add the version parameter “2” to the end of the request.

GET /api/dataquery/get/<secret>/2

Parameters

Response

GET /api/dataquery/get/GXiE4V5qYB
{
    "data": {
        "49": {
            "admin_number_1": "3316",
            "lurits_number_177": "",
            "age_6": "15 years, 200 days",
            "gender_10": "Male"
        },
        "4688": {
            "admin_number_1": "6333",
            "lurits_number_177": "",
            "age_6": "17 years, 10 days",
            "gender_10": "Male"
        }
    },
    "message": "",
    "response": {
        "error": "OK",
        "code": 200
    }
}

The data attribute is a JSON object with zero or more attributes, each being the ID of the relevant data object as specified in the Data Query setup. Each of these objects will have a number of attributes depending on the fields chosen.

Warning

Note that the names of these attributes can be overridden by the school. However, there is a unique numeric identifier that is appended to each which will remain constant. Logic should be based around that identifier.

Note that custom fields will contain the word “custom” before the unique identifier and so that should also be checked for.

GET /api/dataquery/get/GXiE4V5qYB/2

Where the optional parameter “2” is included at the end, the structure of the returned data will change. An additional “fields” property is included with clearer textual descriptions of the fields. The fields in each of the data objects is identified by the immutable identifier. This allows automated systems to ignore parts of the field name that might change.

{
    "fields": [
        {
           "id": 1,
           "name": "Admin Number"
        },
        {
           "id": 177,
           "name": "LURITS Number"
        },
        {
           "id": 6,
           "name": "Age"
        },
        {
           "id": 10,
           "name": "Gender"
        }  
    ],
    "data": {
        "49": {
            "1": "3316",
            "177": "",
            "6": "15 years, 200 days",
            "10": "Male"
        },
        "4688": {
            "1": "6333",
            "177": "",
            "6": "17 years, 10 days",
            "10": "Male"
        }
    },
    "message": "",
    "response": {
        "error": "OK",
        "code": 200
    }
}

DataQuery/getsince:get

See above.

Request

GET /api/dataquery/getsince/<secret>/<timestamp>[/<version>]

Parameters

  • <secret> is the secret defined for a list. This also determines what type of data and which fields are returned.
  • <timestamp> is a Unix integer timestamp - the number of non-leap seconds since 1 January 1970, 00:00:00 UTC. See also Unix Timestamp - Epoch Converter.
  • <version> , if supplied, is the version of the data structure to be returned. See above.

Response

See above.

DataQuery/getone:get

See above.

Request

GET /api/dataquery/getone/<secret>/<identifier>[/<version>]

Parameters

  • <secret> is the secret defined for a list. This also determines what type of data and which fields are returned.
  • <identifier> is the identifier of the dataobject to be returned.
  • <version>, if supplied, is the version of the data structure to be returned. See above.

Response

See above.

Documents/categories:get

Returns a list of document categories that the current API token has any permissions for, along with the permission flags for each.

Request

GET /api/documents/categories

Parameters

None.

Response

The data attribute will be an array of zero or more JSON objects representing categories.

Example:

GET /api/documents/categories
{
    "data": [
        {
            "category_id": 7,
            "category_name": "Photographs",
            "description": "Pupil photographs",
            "parent_id": 1,
            "permissions": {
                "read": true,
                "add": true,
                "delete": false
            }
        }
    ],
    "message": "",
    "response": {
        "error": "OK",
        "code": 200
    }
}
  • category_id is ADAM’s internal identifier for the category.
  • category_name is the display name of the category.
  • description** is the category’s description text.
  • parent_id is the identifier of the parent category (top-level categories have a parent of 0).
  • permissions** indicates which operations the token is allowed to perform on this category.

Documents/list:get

Returns a list of documents for a given entity within a specific category.

Request

GET /api/documents/list/<categoryId>/<entityId>

Parameters

  • categoryId: The ADAM identifier of the document category.
  • entityId: The ADAM identifier of the entity (pupil, staff member, family, or site record).

Response

The data attribute will be an array of zero or more JSON objects representing documents. Requires read permission on the category.

Example:

GET /api/documents/list/108/4561
{
    "data": [
        {
            "document_id": 12345,
            "name": "Birth Certificate",
            "filename": "birth_cert.pdf",
            "filetype": "application/pdf",
            "upload_date": "2025-03-15 10:30:00",
            "category_id": 108,
            "link": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
        }
    ],
    "message": "",
    "response": {
        "error": "OK",
        "code": 200
    }
}
  • document_id is ADAM’s internal identifier for the document.
  • name is the descriptive name given to the document.
  • filename is the original filename of the uploaded file.
  • filetype is the MIME type of the document.
  • upload_date is the date and time the document was uploaded.
  • category_id is the category the document belongs to.
  • link is a unique random string identifier for the document.

Documents/document:get

Returns detailed metadata for a single document, including its entity links.

Request

GET /api/documents/document/<documentId>

Parameters

  • documentId: The ADAM identifier of the document.

Response

The data attribute will be a JSON object with document metadata and linked entities. Requires read permission on the document’s category.

Example:

GET /api/documents/document/12345
{
    "data": {
        "document_id": 12345,
        "name": "Birth Certificate",
        "notes": "",
        "filename": "birth_cert.pdf",
        "filetype": "application/pdf",
        "upload_date": "2025-03-15 10:30:00",
        "category_id": 108,
        "category_name": "Admin Documents",
        "link": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
        "links": [
            {
                "table": "pupils",
                "entity_id": 4561,
                "link_date": "2025-03-15 10:30:00"
            }
        ]
    },
    "message": "",
    "response": {
        "error": "OK",
        "code": 200
    }
}
  • notes is any additional notes attached to the document.
  • category_name is the display name of the document’s category.
  • links is an array of entity associations. Each link contains the entity table (pupils, staff, families, or site), the entity_id, and the link_date.

Documents/download:get

Downloads the binary file content of a document.

Request

GET /api/documents/download/<documentId>

Parameters

  • documentId: The ADAM identifier of the document.

Response

Returns the raw binary file content with the appropriate Content-type header. Requires read permission on the document’s category.

If the document is not found, a standard JSON error response is returned with code 404.

Documents/upload:post

Uploads a new document and links it to an entity.

Request

POST /api/documents/upload

The request body must be JSON with the following fields:

Parameters

  • category (required): The ADAM identifier of the target category.
  • entity_type (required): The type of entity to link the document to. Must be one of: pupils, staff, families, site.
  • entity_id (required): The ADAM identifier of the entity.
  • name (required): A descriptive name for the document.
  • filename (required): The filename (e.g. report.pdf).
  • file_data (required): The file content encoded as a base64 string.
  • mimetype (optional): The MIME type. If omitted, ADAM will attempt to detect it automatically.

Response

Returns the new document’s identifier. Requires add permission on the target category.

Example request body:

{
  "category": 108,
  "entity_type": "pupils",
  "entity_id": 4561,
  "name": "Medical Certificate",
  "filename": "medical.pdf",
  "file_data": "JVBERi0xLjQK..."
}

Example response:

{
  "data": {
    "document_id": 12346,
    "message": "Document uploaded successfully"
  },
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

Documents/document:patch

Updates the metadata of an existing document. Can change the name, notes, or move the document to a different category.

Request

PATCH /api/documents/document/<documentId>

The request body must be JSON with one or more of the following fields:

Parameters

  • documentId (URL): The ADAM identifier of the document.
  • name (optional): New descriptive name for the document.
  • notes (optional): New notes text for the document.
  • category (optional): ADAM identifier of a category to move the document to. The token must also have add permission on the destination category.

Response

Returns a success message. Requires add permission on the document’s current category (and on the destination category if moving).

Example request body:

{
  "name": "Updated Certificate",
  "notes": "Verified by admin"
}

Example response:

{
  "data": {
    "message": "Document updated successfully"
  },
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

Documents/document:delete

Permanently deletes a document and its file from the repository.

Request

DELETE /api/documents/document/<documentId>

Parameters

  • documentId: The ADAM identifier of the document.

Response

Returns a success message. Requires delete permission on the document’s category.

Example:

DELETE /api/documents/document/12345
{
  "data": {
    "message": "Document deleted successfully"
  },
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

Export/families:get

Allows family information to be extracted easily.

Request

GET /api/export/families
GET /api/export/families/all
GET /api/export/families/current
GET /api/export/families?updated_since=2024-10-01+08:15:30
GET /api/export/families/all?updated_since=2024-10-01+08:15:30
GET /api/export/families/current?updated_since=2024-10-01+08:15:30

Parameters

The last parameter (all or current) may be omitted - the default setting is to return current families only. The structure of the data is unchanged.

An optional parameter, updated_since, will only return changes that have been made on or after the time specified. Any valid timestamp, that is URL encoded, can be used.

Note well that changes to email addresses are not reflected in the modified time.

Response

Valid responses will contain an array of family objects in the data property. The family_primary_email and family_secondary_email will be arrays of email addresses:

{
  "data": [
    {
      "family_id": 531,
      "family_admin": "0",
      "family_primary_lastname": "Adamson",
      "family_primary_firstname": "Adam",
      "family_primary_title": "Mr",
      "family_primary_idnum": "1234567890123",
      "family_primary_occupation": "Businessman",
      "family_primary_employer": "ADAM EduTech",
      "family_primary_workphone": "0615096077",
      "family_primary_cell": "0615096077",
      "family_secondary_lastname": "",
      "family_secondary_firstname": "",
      "family_secondary_idnum": "",
      "family_secondary_occupation": "",
      "family_secondary_employer": "",
      "family_secondary_workphone": "",
      "family_secondary_cell": "",
      "family_address_postal_1": "18 Lello Road",
      "family_address_postal_2": "",
      "family_address_postal_suburb": "Assagay",
      "family_address_postal_city": "Outer West Durban",
      "family_address_postal_province": "KwaZulu-Natal",
      "family_address_postal_code": "3600",
      "family_address_postal_country": "South Africa",
      "family_address_residential_1": "18 Lello Road",
      "family_address_residential_2": "",
      "family_address_residential_suburb": "Assagay",
      "family_address_residential_city": "Outer West Durban",
      "family_address_residential_province": "KwaZulu-Natal",
      "family_address_residential_code": "3610",
      "family_address_residential_country": "South Africa",
      "family_notes": "",
      "family_modify": "2024-09-18 08:37:41",
      "family_primary_email": [
        "testing+primary@testing.adam.co.za",
        "testing+primary2@testing.adam.co.za"
      ],
      "family_secondary_email": [
      ]
    }
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

ExternalAuth/auth:post

Allows ADAM to be used as an external authentication source.

Note well: This API endpoint will divulge user information for a valid login name. As with any API key, it is imperative that it is kept secret and changed if a breach is suspected.

Request

POST /api/externalauth/auth/

Parameters

These parameters are sent via form-data parameters.

  • username: The username of the staff member or pupil, or the Identification number or passport number of a family member.
  • password: The password associated with the username

Response

Integrating systems should check the HTTP response code rather than the presence of user information in the data object.

If a valid username and password are supplied, the HTTP response code will be 200. The data object contains the user information and the contained response code will be 200:

{
  "data": {
    "username": "admin",
    "firstname": "Patrick",
    "lastname": "Cloete",
    "email": "testing+staff_1@adam.co.za",
    "type": "staff",
    "id": "1"
  },
  "message": "",
  "response": {
    "error": "Login successful",
    "code": 200
  }
}

If a valid username is supplied, but the password is incorrect, the HTTP response code will be 401. The data object will contain user information and the contained response code will be 401:

{
  "data": {
    "username": "admin",
    "firstname": "Patrick",
    "lastname": "Cloete",
    "email": "testing+staff_1@adam.co.za",
    "type": "staff",
    "id": "1"
  },
  "message": "",
  "response": {
    "error": "Username or password not recognised",
    "code": 401
  }
}

If an invalid username is supplied, the HTTP response code will be 401. The data object will be empty and the contained response code will be 401.

{
  "data": [],
  "message": "",
  "response": {
    "error": "Username or password not recognised",
    "code": 401
  }
}

Pupils/image:get

Returns an image of a pupil.

Request

GET /api/pupils/image/<pupil_id>

Parameters

  • <pupil_id>: The internal identifier of the pupil.

Response

GET /api/reporting/pupils/image/123

Unlike other API calls, this will return an image file and not a JSON object. The image type will be specified by the response’s Content-Type header, but will almost certainly be a JPG image. A response code of 404 suggests that the image does not exist.

Families/currentchildren:get

Request

GET /api/families/currentchildren/<family_id>

Parameters

  • <family_id>: The internal identifier of the family.

Response

This query returns an array of pupils. If no pupils are attached to the family, or if the family identifier does not exist, then the response will be returned with a “404” HTTP status code.

{
  "data": [
    "49",
    "4688"
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

Families/email:get

Get a list of email addresses associated with a family or family member.

Request

GET /api/families/email/<family_id>[/(primary|secondary)]

Parameters

  • <family_id>: The internal identifier of the family.
  • (primary|secondary): OPTIONAL - whether to return only email addresses of the primary or secondary parent

Response

This query returns an array of zero or more email address records.

{
  "data": [
    {
      "email_id": 9372,
      "email_family_id": 123,
      "email_member": "primary",
      "email_address": "testing+245@test.adam.co.za",
      "email_description": "",
      "email_bulkmail": "Yes",
      "email_reports": "Yes",
      "email_alerts": "Yes",
      "email_maillog": "Yes",
      "email_modify": "2025-02-21 12:00:42"
    }
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

Families/email:post

Add an email address to a family member.

Request

POST /api/families/email/<family_id>/(primary|secondary)

Parameters

  • <family_id>: The internal identifier of the family.
  • (primary|secondary): Which parent the email address should be added to

In the POST body:

  • email: a string containing the email address

Response

“201 Created” if added successfully, 200 if not added, with an appropriate error message in the response.error property (e.g. the email address may already exist?).

Families/email:delete

Remove an email address to a family member.

Request

DELETE /api/families/email/<family_id>/(primary|secondary)

Parameters

  • <family_id>: The internal identifier of the family.
  • (primary|secondary): Which parent the email address should be added to

In the body which must be x-www-form-urlencoded:

  • email: a string containing the email address to delete

Response

200 if deleted successfully, 404 if not found, with an appropriate error message in the response.error property.

Families/searchbyid:get

Request

GET /api/families/searchbyid/<RSA_ID_Number>

Parameters

  • <RSA_ID_Number>: A South African ID number or international passport number for parents without an ID number. The parameter should be trimmed of spaces. This performs a simple text match with the database field and thus relies on reasonable data hygiene.

Response

This response returns an array of generally one family identifier, but if an ID number is associated with many parents, all will be returned in the array. This is discouraged in the interface, but schools may still do this.

Where the ID number cannot be found, a response will be returned with an HTTP 404 status code.

{
  "data": [
    "1234"
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

Families/children:get

Returns the children linked to a family. Alias: families/get_children_by_family.

Request

GET /api/families/children/<family>

Parameters

  • <family>: ADAM internal family identifier (required)

Response

Data attribute contains an array of child records with pupil details, grade, and default class status.

{
  "data": [
    {
      "pupil_id": 1234,
      "pupil_lastname": "Smith",
      "pupil_firstname": "John",
      "pupil_grade": "Grade 10",
      "pupil_defaultclass": "10A"
    }
  ]
}

Note: Pupils at the “pre” (admissions) stage show “Admission” instead of a class name, and will show their current grade rather than their grade of entry.

Families/contactlist:get

Returns contact details for all families.

Request

GET /api/families/contactlist

Parameters

None.

Response

{
  "data": [
    {
      "id": 500,
      "primary": {
        "firstname": "Jane",
        "lastname": "Smith",
        "cell": "0821234567",
        "email": ["jane@example.com"]
      },
      "secondary": {
        "firstname": "John",
        "lastname": "Smith",
        "cell": "0829876543",
        "email": ["john@example.com"]
      }
    }
  ]
}

If no secondary contact exists, the secondary field is an empty array.

Families/familyrelationships:get

Returns all pupil-to-family relationship mappings.

Request

GET /api/families/familyrelationships

Parameters

None.

Response

{
  "data": [
    { "pupil": 1234, "family": 500 },
    { "pupil": 1235, "family": 500 }
  ]
}

Families/fields:get

Returns the list of valid fields for family records.

Request

GET /api/families/fields/<action>

Parameters

  • <action>: Action context (optional; e.g. “add” or “edit” to filter relevant fields)

Response

Data attribute contains a mapping of field names to their descriptions.

Families/add:post

Creates a new family record.

Request

POST /api/families/add

Parameters

JSON request body containing family fields. Use families/fields to retrieve valid field names.

Response

  • Code 200: Returns the new family ID
  • Code 400: Validation error — response includes list of invalid fields

Families/family:patch

Updates an existing family record.

Request

PATCH /api/families/family/<family>

Parameters

  • <family>: ADAM internal family identifier (URL path parameter)
  • JSON request body containing fields to update

Response

  • Code 200: Returns the updated family record
  • Code 400: Validation error
  • Code 404: Family not found

Families/link:post

Links a pupil to a family with specified relationship types.

Request

POST /api/families/link

Parameters

JSON request body:

{
  "family_id": 500,
  "pupil_id": 1234,
  "primary_relationship": "biological",
  "secondary_relationship": "biological"
}

Valid relationship types: biological, adoptive parent, step parent, foster parent, guardian, sponsor, relative, other.

Response

Code 200 on success.

Families/detailsupdateform:get

Triggers an email to the family with a details update form.

Request

GET /api/families/detailsupdateform/<family>

Parameters

  • <family>: ADAM internal family identifier (required)

Response

No data returned.

  • Code 200: “Detail update form sent.”
  • Code 500: Error sending form

FamilyLogin/privileges:get

Returns the portal permissions available for the currently authenticated family or pupil login.

Request

GET /api/familylogin/privileges

Parameters

None — uses the current authentication session context.

Response

Data attribute maps pupil IDs to their available permission strings.

{
  "data": {
    "1234": ["marks", "reports", "absentee", "stats"],
    "1235": ["marks", "reports"]
  }
}

FamilyRelationships/family:get

Gets a list of current pupils linked to a family with their relationships descriptors for primary and secondary parents.

Request

GET /api/familyrelationships/family[/<family_id>]

Parameters

  • <family_id>: The internal identifier for the family. If omitted, all families are returned.

Response

The data attribute contains an array of 0 or more objects.

  • The index of each array object is the identifier of the pupil.
  • A primary and secondary key contain the relationship between the primary or secondary family member and the pupil. Note that a relationship will be returned even in instances where there may not be a secondary family member. Other logic must determine whether to discard this value or not.

Possible values include:

  • biological
  • adoptive parent
  • stepparent
  • foster parent
  • guardian
  • sponsor
  • relative
  • Other
GET /api/familyrelationships/family/123
{
  "data": [
    {
      "111": {
        "primary": "biological",
        "secondary": "step parent"
      },
      "321": {
        "primary": "step parent",
        "secondary": "biological"
      }
    }
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

FamilyRelationships/pupil:get

Gets a list of families linked to a pupil with their relationships descriptors for primary and secondary parents.

Request

GET /api/familyrelationships/pupil[/<pupil_id>]

Parameters

  • <pupil_id>: The internal identifier for the pupil. If omitted, all pupils are returned

Response

GET /api/familyrelationships/pupil/123
{
  "data": {
    "111": {
      "primary": "biological",
      "secondary": "step parent"
    },
    "321": {
      "primary": "step parent",
      "secondary": "biological"
    }
  },
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

The data attribute contains an array of 0 or more objects.

  • The index of each array object is the identifier of the family.
  • A primary and secondary key contain the relationship between the primary or secondary family member and the pupil. Note that a relationship will be returned even in instances where there may not be a secondary family member. Other logic must determine whether to discard this value or not.

Possible values include:

  • biological
  • adoptive parent
  • step parent
  • foster parent
  • guardian
  • sponsor
  • relative
  • Other
GET /api/familyrelationships/pupil
{
  "data": {
    "123": {
      "111": {
        "primary": "biological",
        "secondary": "step parent"
      },
      "321": {
        "primary": "step parent",
        "secondary": "biological"
      }
    },
    "456": {
      "111": {
        "primary": "step parent",
        "secondary": "biological"
      }
    }
  },
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

FormFields/fields:get

Returns field definitions for a specified database table.

Request

GET /api/formfields/fields/<table>/<action>

Parameters

  • <table>: Table name (required)
  • <action>: Action context (optional)

Response

Data attribute maps field names to their descriptions.

Leaves/approved:get

Gets a list of approved leaves with an end date that is either today or in the future.

Request

GET /api/leaves/approved[/<pupil>]

Parameters

  • <pupil>: Optional: The identifier of the pupil in question.

Response

GET /api/leaves/approved/6050
{
  "data": [
    {
      "leave_request_id": 4765,
      "leave_request_out": "2024-10-18 14:15:00",
      "leave_request_in": "2024-10-20 18:30:00",
      "leave_request_destination": "Home",
      "leave_request_host": "Parents",
      "leave_request_host_contact": "083",
      "leave_request_notes": "thanks",
      "leave_request_approval_notes": "\\n",
      "leave_request_status": "Approved",
      "leave_request_user_id": 1,
      "leave_request_user_type": "staff",
      "leave_request_submitted_datetime": "2024-10-15 10:37:01",
      "leave_request_reminder_datetime": null,
      "leave_request_choices": "Will he need Saturday Lunch:No\\nWill he need Sunday Supper:No\\nDo you need a gate code:No\\n",
      "leave_type_id": 1,
      "leave_type_description": "Full Weekend Leave",
      "leave_type_overnight": "Yes",
      "leave_type_off_campus": "Yes"
    }
  ],
  "message": "Leaves for Joseph Tshabalala",
  "response": {
    "error": "OK",
    "code": 200
  }
}

The data attribute contains an array of 0 or more leave records.

Medical/offsport:get

Returns a list of pupil IDs currently off sport due to medical reasons.

Request

GET /api/medical/offsport/<date>

Parameters

  • <date>: ISO-formatted date (optional; defaults to current date)

Response

{
  "data": [1234, 1567, 1890],
  "message": "Offsport list for 2026-04-09.",
  "response": { "error": "OK", "code": 200 }
}

MessagingLogs/messages:get

Returns 20 delivered messages for a family or pupil, paginated.

Request

GET /api/messaginglogs/messages/<type>/<id>[/<start>]

Parameters

  • <type>: family or pupil (required)
  • <id>: Family or pupil identifier (required)
  • <start>: Pagination offset (optional; defaults to 0). Returns 20 messages per page.

Response

Data attribute contains an array of delivered message summaries.

MessagingLogs/message:get

Returns a single message’s details.

Request

GET /api/messaginglogs/message/<type>/<id>/<messageId>

Parameters

  • <type>: family, pupil, or staff (required)
  • <id>: Identifier for the family, pupil, or staff member (required)
  • <messageId>: Message identifier (required)

Response

Data attribute contains the full message details.

MessagingLogs/messagebyid:get

Returns a message by its ID, including attachments.

Request

GET /api/messaginglogs/messagebyid/<messageId>

Parameters

  • <messageId>: Message identifier (required)

Response

Data attribute contains the message with an attachments array:

{
  "data": {
    "message_id": 42,
    "subject": "Newsletter",
    "body": "...",
    "attachments": [
      { "link": "/path/to/file", "location": "docrep", "name": "Newsletter.pdf" }
    ]
  }
}

Permissions

Requires one of: messagelog_staff_view, messagelog_family_view, messagelog_pupil_view (staff tokens); or viewmessagelog_family, viewmessagelog_pupil (family/pupil tokens).

Psychometric/assessmentsbycategory:get

Returns active psychometric assessments for a category. Alias: psychometric/assessments_by_category.

Request

GET /api/psychometric/assessmentsbycategory/<category>

Parameters

  • <category>: Psychometric category identifier (required)

Response

Data attribute contains an array of active assessment records (where assessment_disabled = ‘No’).

Pupils/add:post

Request

POST /api/pupils/add

Parameters

The body of the request is a JSON object of field names and values.

{
  "pupil_id": 123,
  "pupil_lastname": "Adams",
  "pupil_firstname": "Adam",
  ...
}

Response

The response code will determine whether the pupil was added or not, with invalid requests returning a 400 error. Acceptable field names can be inspected by using the pupils/pupil:get endpoint. The following fields are mandatory:

  • pupil_lastname - the pupil’s last name
  • pupil_firstname - the pupil’s preferred legal name
  • pupil_fullfirst - the pupil’s full names, excluding last name
  • pupil_final - the pupil’s estimated Grade 12 year (NB - this must be the year of their Grade 12 year, even at a primary school level. ADAM uses this year to calculate the current grade a pupil is in)
  • pupil_entry - the date when a pupil will enter the school. For pupils starting school at the start of an academic year, it is suggested to use is ‘year-01-01’ rather than the first day of term.

Note that while pupils may be added to the database even if these fields are omitted, doing so will make the pupils nearly impossible to manage on the receiving end.

For fields ending in an “_id” suffix, some values can be determined from Appendix A. Note that pupil_registration_id field refers to a many-to-many relationship and thus cannot be completed by this end-point. If it exists in the submitted data, it is silently discarded.

If any other invalid fields are passed in, the response message will contain details of those invalid fields.

Pupils/image:get

Request

GET /api/pupils/image/<ADAM_Identifier>[/<width>]

Parameters

  • <ADAM_Identifier>: An integer referring to the pupil’s internal ADAM identifier.
  • <width>: An optional integer to determine the maximum width of the image. If omitted, the image is not resized. If the width provided is larger than the image’s width, the image will not be resized.

Response

This response returns an image. No JSON information is returned.

Where the identifier cannot be found, a response will be returned with an HTTP 404 status code.

Pupils/pupil:get

Request

GET /api/pupils/pupil/<ADAM_Identifier>

Parameters

  • <ADAM_Identifier>: An integer referring to the pupil’s internal ADAM identifier.

Response

This response returns a JSON object of data for a single pupil.

Where the identifier cannot be found, a response will be returned with an HTTP 404 status code.

{
  "data": {
    "pupil_id": 123,
    "pupil_lastname": "Adams",
    "pupil_firstname": "Adam",
    ...
  },
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

Pupils/search-admin:get

Request

GET /api/pupils/search-admin/<AdminNumber>

Parameters

  • <AdminNumber>: The school-assigned administration number for a pupil. The parameter should be trimmed of spaces. This performs a simple text match with the database field and thus relies on reasonable data hygiene.

Response

This response returns an array of generally one pupil identifier, but if an Admin number is associated with many pupils, all will be returned in the array. This is discouraged in the interface, but schools may still do this.

Where the Admin number cannot be found, a response will be returned with an HTTP 404 status code.

{
  "data": [
    "1234"
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

Pupils/searchbyid:get

Request

GET /api/pupils/search-id/<RSA_ID_Number>
GET /api/pupils/searchbyid/<RSA_ID_Number>

Parameters

  • <RSA_ID_Number>: A South African ID number or international passport number for pupils without an ID number. The parameter should be trimmed of spaces. This performs a simple text match with the database field and thus relies on reasonable data hygiene.

Response

This response returns an array of generally one pupil identifier, but if an ID number is associated with many pupils, all will be returned in the array. This is discouraged in the interface, but schools may still do this.

Where the ID number cannot be found, a response will be returned with an HTTP 404 status code.

{
  "data": [
    "1234"
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

Pupils/fields:get

Returns the list of valid fields for pupil records.

Request

GET /api/pupils/fields/<action>

Parameters

  • <action>: Action context (optional; e.g. “add” or “edit”)

Response

Data attribute maps field names to their descriptions.

Pupils/pupil:patch

Updates an existing pupil record.

Request

PATCH /api/pupils/pupil/<pupil>

Parameters

  • <pupil>: ADAM internal pupil identifier (URL path parameter)
  • JSON request body containing fields to update

Response

  • Code 200: Returns the updated pupil record (includes pupil_gender as name and pupil_grade)
  • Code 400: Validation error
  • Code 404: Pupil not found

Pupils/contactlist:get

Returns contact details for all pupils.

Request

GET /api/pupils/contactlist

Parameters

None.

Response

{
  "data": [
    {
      "id": 1234,
      "firstname": "John",
      "lastname": "Smith",
      "cell": "0821234567",
      "email": "john@example.com",
      "grade": "Grade 10"
    }
  ]
}

Pupils/search-id:get

Searches for pupils by ID number. Alias: pupils/searchbyid (note: this is a different endpoint from the documented Pupils/searchbyid which searches by admin number — verify the documented version is correct).

Request

GET /api/pupils/search-id/<idNumber>

Parameters

  • <idNumber>: ID number to search for (required)

Response

  • Code 200: Array of matching pupil IDs
  • Code 400: Empty idNumber parameter
  • Code 404: No pupils found

RecordsAndPoints/recentpupilrecords:get

Returns the most recent Records and Points entries for a pupil.

Request

GET /api/recordsandpoints/recentpupilrecords/<pupil>[/<number>]

Parameters

  • <pupil>: ADAM internal pupil identifier (required)
  • <number>: Maximum number of records to return (optional; defaults to 10)

Response

{
  "data": [
    {
      "group_name": "Bad",
      "category_description": "Demerit",
      "discipline_date": "2026-04-01 08:30:00",
      "discipline_effective_date": "2026-04-01",
      "discipline_amount": 1,
      "discipline_notes": "Late to class",
      "option_description": null
    }
  ]
}

RecordsAndPoints/pupilrecords:get

Returns all Records and Points entries for a pupil, grouped by category group and category.

Request

GET /api/recordsandpoints/pupilrecords/<pupil>

Parameters

  • <pupil>: ADAM internal pupil identifier (required)

Response

Data attribute is a nested structure grouped by discipline group, then by category, with all records within each category.

{
  "data": {
    "1": {
      "group_name": "Bad",
      "discipline_categories": [
        {
          "category_description": "Demerit",
          "discipline_records": [
            {
              "discipline_date": "2026-04-01",
              "discipline_amount": 1,
              "discipline_notes": "Late to class"
            }
          ]
        }
      ]
    }
  }
}

Registration/status:post

Updates the registration status of a pupil by adding a record to their registration status log.

Request

POST /api/registration/status/<pupil>

Parameters

URL parameters:

  • <pupil>: The identifier of the pupil whose registration status is to be changed.

These parameters are sent via form-data parameters.

  • status: The identifier of the new registration status
  • notes: Notes to add to the registration status

Response

If the request was successful, a 200 OK code is returned. If an invalid status was chosen, a 400 Bad Request code is returned.

This endpoint is restricted in that updating the registration status of a pupil cannot change the “stage” of a pupil’s registration (a “stage” being one of “admissions”, “current enrolment” or “alumni”). Changing to a new stage requires additional processing to be done within ADAM and so attempts to change between statuses that are from different stages will be responded to with a 400 code.

Registration/statuses:get

Gets a list of registration statuses that are active on the system.

Request

GET /api/registration/statuses

Parameters

None

Response

GET /api/registration/statuses
{
  "data": [
    {
      "status_id": 1,
      "status_description": "Applicant",
      "status_stage": "pre",
      "status_active": "Yes",
      "status_default": "Yes",
      "status_official": "Yes",
      "status_familyshow": "Yes",
      "status_sortorder": 1
    }
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}
  • status_stage is an enum with values pre (pre-admission), current (pupils enrolled in the school) or post (alumni and graduated pupils).

The following boolean values are also given:

  • status_active: Whether the pupil record is active or inactive. Inactive pupils might include those who have withdrawn from the registration process, withdrawn from the school, died, and so on. When combined with status_stage, this provides six broad categories of registration status.
  • status_default: Each of the three status_stage values has one default status. This is automatically applied to pupils entering this stage for the first time.
  • status_official: Whether this status refers to an official enrolment or not. Unofficial enrolments may include exchange or visiting pupils.
  • status_familyshow: Whether or not pupils with this status should be shown on the family portal. For example, it can be distressing for parents of a deceased child to see that child appear on their family portal landing page. Similarly, withdrawn pupils might not show, but graduated pupils should.

Registration/statuslist:get

Gets a list of pupils who belong to a specific registration status

Request

GET /api/registration/statuslist/<status>

Parameters

  • <status>: The identifier of the registration status.

Response

GET /api/registration/statuslist/2
{
  "data": [
    1,
    123,
    4321
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

The data attribute contains an array of 0 or more integers representing the identifiers of pupils who belong to this registration status.

Registrations/grade:get

Returns a list of classes that a grade of pupils is registered for.

Request

GET /api/registrations/grade/<grade>

Parameters

  • <grade> is an integer representing the grade of pupils to retrieve from the database. Note that 0 represents Grade R and negative grades represent the pre-school grades.

Response

The response is an array of pupil registration objects, each following the structure below:

{
  "data": [
    {
      "registration_id": 162555,
      "pupil_id": 1234,
      "pupil_lastname": "Last-Name",
      "pupil_firstname": "First",
      "class_id": 4231,
      "class_description": "Z",
      "class_gradeyear": "11",
      "subject_id": 101,
      "subject_name": "English Home Language",
      "subject_short": "Eng",
      "category_id": 1,
      "category_description": "Academic",
      "registration_datestart": "2024-01-20",
      "registration_dateend": null,
      "staff_id": 123,
      "staff_firstname": "Educator",
      "staff_lastname": "Mary"
    }
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

Reporting/periods:get

Gets a list of reporting periods for a year.

Request

GET /api/reporting/periods[/<year>]

Parameters

  • <year>: OPTIONAL. The calendar year in question. If omitted, the current calendar year is used.

Response

GET /api/reporting/periods/2018
{
  "data": [
    {
      "period_id": "31",
      "period_name": "Term 1",
      "period_start": "2018-01-01",
      "period_end": "2018-12-02",
      "period_publish": "2018-12-02 12:00:00"
    }
  ],
  "message": "Reporting periods from year 2018",
  "response": {
    "error": "OK",
    "code": 200
  }
}

The data attribute contains an array of 0 or more reporting period objects.

  • period_id is the internal identifier for the reporting period in question.
  • period_name is the user-provided descriptor for that reporting period.
  • period_start is the starting date of the reporting period. This is often set as the start of term, but some schools, who run concurrent or additional reporting periods may not align reporting periods with terms.
  • period_end is the date on which the reporting period is deemed to have finished.
  • period_publish is the date and time when the reports are made available on the parent portal. This date may change at the user discretion and so this value should always be double checked on or after this time if important actions are to occur.

Reporting/results:get

Gets all academic results for a reporting period.

Request

GET /api/reporting/results/<reportingperiod>

Parameters

  • <reportingperiod> is the value of the reporting period identifier. See the period_id property returned in the Reporting/periods/get request above.

Response

GET /api/reporting/results/31
{
  "data": [
    {
      "pupil_id": 1754,
      "pupil_admin": "55012",
      "pupil_grade": 9,
      "results": [
        {
          "subject_id": 1,
          "subject_name": "English",
          "dbe_subject_code": "",
          "result_term": 50,
          "result_ytd": 50
        },
        {
          "subject_id": 40,
          "subject_name": "Technology",
          "dbe_subject_code": "15351142",
          "result_term": null,
          "result_ytd": null
        }
      ],
      "report_aggregate": 72.5,
      "report_aggregate_ytd": 72.5,
      "report_modified": "2016-02-11 11:36:17"
    }
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

The data attribute contains an array of 0 or more pupil objects. The pupil object has the following attributes:

  • pupil_id the internal identifier of the pupil.
  • pupil_admin is a user-provided identifier. These should be consistent but can change at the school’s discretion.
  • pupil_grade gives the grade that the pupil was in for this reporting period. Values are integers between -3 (Grade 0000) and 13 (Post Matric).
  • results is an array of 0 or more subject result objects. These objects have the following properties:

  • subject_id is the internal identifier for the subject in ADAM. Note that these may not be consistent as some schools have multiple versions of the same subject (e.g. English for Junior School vs English for High School). These values are not consistent across schools.

  • subject_name is the user-provided name for that subject.
  • dbe_subject_code is the Department of Basic Education’s subject code. Typically, this is specific to the grade and subject. Because some schools offer their curriculum in different configurations, some codes may be duplicated, and yet other subjects may not have a code assigned (which is represented by an empty string).
  • result_term is the pupil’s result for this reporting period (normally akin to a term). A null value represents an absent result. This result is otherwise returned as a float and decimal places should be anticipated
  • result_ytd is the pupil’s year-to-date result, a result that is often an aggregated result across a number of reporting periods. A null value represents an absent result.This result is otherwise returned as a float and decimal places should be anticipated.

  • report_aggregate is a summary result (often, but not always, an average of all the subject results) for the pupil for that term.

  • report_aggregate_ytd is a summary year-to-date result. Again, this is often, but not always an average of the subject results.
  • report_modified is a timestamp of the last modification time of that report.

Reporting/pupilreportingperiods:ge

Returns reporting periods available for a specific pupil, including report availability.

Request

GET /api/reporting/pupilreportingperiods/<pupil>

Parameters

  • <pupil>: ADAM internal pupil identifier (required)

Response

{
  "data": [
    {
      "period_id": 3,
      "period_name": "Term 1 2026",
      "period_start": "2026-01-15",
      "period_end": "2026-03-31",
      "period_publish": "Yes",
      "report_aggregate": 72.5,
      "report_aggregate_ytd": 72.5,
      "document_id": 456,
      "document_upload_date": "2026-04-01",
      "pupil_gradetext": "Grade 10"
    }
  ]
}

Reporting/subjectmarksbypupil:get

Returns subject marks for a pupil across all reporting periods.

Request

GET /api/reporting/subjectmarksbypupil/<pupil>

Parameters

  • <pupil>: ADAM internal pupil identifier (required)

Response

Data attribute contains an array of reporting periods, each with a nested subjects array:

{
  "data": [
    {
      "period_id": 3,
      "period_name": "Term 1 2026",
      "subjects": [
        {
          "subject_id": 5,
          "grade": 10,
          "subject_name": "Mathematics",
          "subject_short": "Maths",
          "teacher_email": "smith@school.co.za",
          "teacher_name": "Mr Smith",
          "result": 78,
          "class_friendly": "10A Maths"
        }
      ]
    }
  ]
}

Reporting/markbook:get

Returns the markbook (assessment results by category) for a pupil in a specific reporting period.

Request

GET /api/reporting/markbook/<period>/<pupil>

Parameters

  • <period>: Reporting period identifier (required)
  • <pupil>: ADAM internal pupil identifier (required)

Response

Data attribute contains an array of subjects with assessment categories and individual assessments.

{
  "data": [
    {
      "subject_name": "Mathematics",
      "subject_short": "Maths",
      "class_teacher": "Mr Smith",
      "class_gradeyear": 10,
      "class_description": "10A",
      "class_friendly": "10A Maths",
      "assessment_categories": [
        {
          "category_name": "Tests",
          "assessments": []
        }
      ]
    }
  ]
}

Reporting/report:get

Returns a pupil’s report as a PDF document.

Request

GET /api/reporting/report/<period>/<pupil>

Parameters

  • <period>: Reporting period identifier (required)
  • <pupil>: ADAM internal pupil identifier (required)

Response

Binary PDF response with content type application/pdf.

Reporting/previousreports:get

Returns historical report information for a pupil.

Request

GET /api/reporting/previousreports/<pupil>

Parameters

  • <pupil>: ADAM internal pupil identifier (required)

Response

Data attribute contains previous report table data.

Report detail endpoints and publication

The four reporting/… endpoints that follow (and their reporting/grade/… counterparts) expose the detail that appears on a pupil’s printed report — subject comments, learning outcomes, assessment standards and behavioural indicators — as JSON. Every value is read through the same report engine that renders the PDF, so the figures match the printed report exactly.

Only published reporting periods are exposed. A period is published once its publish date and time has passed (see period_publish under Reporting/periods). Behaviour for the period identifier supplied in the request:

  • Period not yet published → 403 (Forbidden), with no data.
  • Period identifier not recognised → 400 (Bad Request).
  • Published period with no captured detail → 200 (OK) with an empty data array.

Wherever a value has not been captured it is returned as null. This covers absent marks and any text field left blank on the report.

Reporting/comments:get

Returns the subject comments and result summary for a pupil’s report in a published reporting period.

Request

GET /api/reporting/comments/<pupil>/<period>

Parameters

  • <pupil>: ADAM internal pupil identifier (required).
  • <period>: Reporting period identifier (required). The period must be published (see the note above).

Response

The data attribute contains an array with one object per reporting subject on the pupil’s report.

{
  "data": [
    {
      "subject_id": 5,
      "subject_name": "Mathematics",
      "subject_short": "Maths",
      "subject_category_id": 2,
      "class_id": 812,
      "class_friendly": "10A Maths",
      "teacher_name": "Mr Smith",
      "comment": "A pleasing term's work.",
      "comment_generic": null,
      "result_term": 78,
      "result_ytd": 74.5,
      "symbol_term": "B",
      "symbol_ytd": "B",
      "level": null
    }
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}
  • subject_id is the internal identifier for the subject in ADAM (see Reporting/results).
  • subject_name is the subject’s full name.
  • subject_short is the subject’s short name.
  • subject_category_id is the identifier of the subject category the subject belongs to.
  • class_id is the identifier of the class the pupil is registered in for this subject.
  • class_friendly is a human-readable class name, or null if none is configured.
  • teacher_name is the class teacher’s name, or null.
  • comment is the pupil’s subject comment for this period, or null if none was captured.
  • comment_generic is the generic (shared) subject comment, or null.
  • result_term is the term result as a float, or null if absent.
  • result_ytd is the year-to-date result as a float, or null if absent.
  • symbol_term is the term result symbol, or null.
  • symbol_ytd is the year-to-date result symbol, or null.
  • level is the subject level descriptor, or null.

Reporting/outcomes:get

Returns the learning outcomes captured on a pupil’s report in a published reporting period.

Request

GET /api/reporting/outcomes/<pupil>/<period>

Parameters

  • <pupil>: ADAM internal pupil identifier (required).
  • <period>: Reporting period identifier (required). The period must be published (see the note above).

Response

The data attribute contains an array with one object per populated learning outcome, across all of the pupil’s subjects. Outcomes with no captured value are omitted, matching the printed report.

{
  "data": [
    {
      "subject_id": 5,
      "outcome_id": 41,
      "outcome_number": "1",
      "outcome_name": "Numbers, Operations and Relationships",
      "outcome_description": "Recognises, describes and represents numbers.",
      "symbol": "4",
      "symbol_name": "Adequate",
      "symbol_description": "Adequate achievement (50 – 59%)",
      "mark": null,
      "weighting": 25,
      "comment": null
    }
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}
  • subject_id is the subject the learning outcome belongs to.
  • outcome_id is the internal identifier of the learning outcome.
  • outcome_number is the outcome’s display number.
  • outcome_name is the outcome’s name.
  • outcome_description is the outcome’s longer description.
  • symbol is the captured symbol/level for the outcome, or null.
  • symbol_name is the name associated with that symbol, or null.
  • symbol_description is the description associated with that symbol, or null.
  • mark is the numeric mark for the outcome as a float, or null when the outcome is assessed by symbol rather than a mark.
  • weighting is the outcome’s weighting as a float, or null.
  • comment is the outcome comment, or null.

Reporting/standards:get

Returns the assessment standards captured on a pupil’s report in a published reporting period.

Request

GET /api/reporting/standards/<pupil>/<period>

Parameters

  • <pupil>: ADAM internal pupil identifier (required).
  • <period>: Reporting period identifier (required). The period must be published (see the note above).

Response

The data attribute contains an array with one object per assessment standard that has a captured symbol, across all of the pupil’s learning outcomes. Standards with no captured symbol are omitted, matching the printed report.

{
  "data": [
    {
      "subject_id": 5,
      "outcome_id": 41,
      "criterion_id": 233,
      "criterion_number": "1.1",
      "criterion_name": "Counts objects",
      "criterion_description": "Counts to at least 100 everyday objects reliably.",
      "symbol": "3"
    }
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}
  • subject_id is the subject the assessment standard belongs to.
  • outcome_id is the learning outcome the standard falls under.
  • criterion_id is the internal identifier of the assessment standard (criterion).
  • criterion_number is the standard’s display number, or null.
  • criterion_name is the standard’s name, or null.
  • criterion_description is the standard’s longer description, or null.
  • symbol is the captured symbol for the standard, or null.

Reporting/indicators:get

Returns the behavioural indicators captured on a pupil’s report in a published reporting period.

Request

GET /api/reporting/indicators/<pupil>/<period>

Parameters

  • <pupil>: ADAM internal pupil identifier (required).
  • <period>: Reporting period identifier (required). The period must be published (see the note above).

Response

The data attribute contains an array with one object per behavioural indicator captured against a subject. Behavioural indicators are configured per grade and period, so a period/grade without a behavioural-indicator configuration returns an empty array.

{
  "data": [
    {
      "subject_id": 5,
      "descriptor": "Participates in class",
      "value": "Often"
    }
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}
  • subject_id is the subject the behavioural indicator was captured against.
  • descriptor is the behavioural indicator descriptor.
  • value is the captured value for the indicator, or null.

Reporting/grade/comments:get

Returns the same detail as Reporting/comments, but for every pupil registered for a given subject in a given grade during a published reporting period, rather than a single pupil.

Each row carries two extra leading keys — pupil_id and pupil_admin — identifying the pupil the row belongs to. The remaining keys are exactly those of the pupil-scoped endpoint. The publication rules and null handling described in the note above apply identically.

Request

GET /api/reporting/grade/comments/<grade>/<subject>/<period>

Parameters

  • <grade>: The grade identifier (required). Values are integers between -3 (Grade 0000) and 13 (Post Matric); negative values denote pre-primary grades.
  • <subject>: The internal subject identifier (required).
  • <period>: Reporting period identifier (required). The period must be published (see the note above).

Response

The data attribute contains an array with one object per subject per pupil in the cohort.

{
  "data": [
    {
      "pupil_id": 1754,
      "pupil_admin": "55012",
      "subject_id": 5,
      "subject_name": "Mathematics",
      "subject_short": "Maths",
      "subject_category_id": 2,
      "class_id": 812,
      "class_friendly": "10A Maths",
      "teacher_name": "Mr Smith",
      "comment": "A pleasing term's work.",
      "comment_generic": null,
      "result_term": 78,
      "result_ytd": 74.5,
      "symbol_term": "B",
      "symbol_ytd": "B",
      "level": null
    }
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}
  • pupil_id is the internal identifier of the pupil the row belongs to.
  • pupil_admin is that pupil’s user-provided identifier.
  • All remaining fields are as described under Reporting/comments.

Reporting/grade/outcomes:get

Returns the same detail as Reporting/outcomes, for every pupil registered for a given subject in a given grade during a published reporting period. Each row is prefixed with pupil_id and pupil_admin; the remaining fields match the pupil-scoped endpoint.

Request

GET /api/reporting/grade/outcomes/<grade>/<subject>/<period>

Parameters

  • <grade>: The grade identifier (required). Values are integers between -3 (Grade 0000) and 13 (Post Matric); negative values denote pre-primary grades.
  • <subject>: The internal subject identifier (required).
  • <period>: Reporting period identifier (required). The period must be published (see the note above).

Response

As Reporting/outcomes, with each row prefixed by pupil_id and pupil_admin.

Reporting/grade/standards:get

Returns the same detail as Reporting/standards, for every pupil registered for a given subject in a given grade during a published reporting period. Each row is prefixed with pupil_id and pupil_admin; the remaining fields match the pupil-scoped endpoint.

Request

GET /api/reporting/grade/standards/<grade>/<subject>/<period>

Parameters

  • <grade>: The grade identifier (required). Values are integers between -3 (Grade 0000) and 13 (Post Matric); negative values denote pre-primary grades.
  • <subject>: The internal subject identifier (required).
  • <period>: Reporting period identifier (required). The period must be published (see the note above).

Response

As Reporting/standards, with each row prefixed by pupil_id and pupil_admin.

Reporting/grade/indicators:get

Returns the same detail as Reporting/indicators, for every pupil registered for a given subject in a given grade during a published reporting period. Each row is prefixed with pupil_id and pupil_admin; the remaining fields match the pupil-scoped endpoint.

Request

GET /api/reporting/grade/indicators/<grade>/<subject>/<period>

Parameters

  • <grade>: The grade identifier (required). Values are integers between -3 (Grade 0000) and 13 (Post Matric); negative values denote pre-primary grades.
  • <subject>: The internal subject identifier (required).
  • <period>: Reporting period identifier (required). The period must be published (see the note above).

Response

As Reporting/indicators, with each row prefixed by pupil_id and pupil_admin.

Request/test:get

A test method to the API.

Request

GET /api/request/test/[Parameter1]/[Parameter2]

Parameters

[Parameter1]: An arbitrary parameter that is returned.

[Parameter2]: An arbitrary parameter that is returned.

Output

The output data will be a JSON object containing attributes parameter1 and parameter2, both of which will contain the values provided in the request.

Example:

https://demo.adam.co.za/api/request/test/First%20Parameter/Second
{
  "data": {
    "parameter1": "First Parameter",
    "parameter2": "Second"
  },
  "message": "Hello, you're speaking to Random High School's ADAM. We are currently on revision 6125 and the local time is 11:26:46.",
  "response": {
    "error": "OK",
    "code": 200
  }
}

Staff/image:get

Returns an image of a staff member.

Request

GET /api/staff/image/<staff_id>

Parameters

  • <staff_id>: The internal identifier of the pupil.

Response

GET /api/reporting/staff/image/123

Unlike other API calls, this will return an image file and not a JSON object. The image type will be specified by the response’s Content-Type header, but will almost certainly be a JPG image. A response code of 404 suggests that the image does not exist.

Subjects/get_by_grades:get

Returns subjects available for one or more grades.

Request

GET /api/subjects/get_by_grades/<grades>

Parameters

  • <grades>: Comma-separated list of grade identifiers (required)

Response

Data attribute contains an array of subjects valid for the specified grades that have active class registrations.

Subjects/get_by_grade:get

Returns subjects available for a single grade.

Request

GET /api/subjects/get_by_grade/<grade>

Parameters

  • <grade>: Grade identifier (required)

Response

Data attribute contains an array of subjects for the specified grade with active class registrations.

TableFields/fields:get

Returns field definitions for a specified database table. Similar to FormFields/fields but uses the TableFields system.

Request

GET /api/tablefields/fields/<table>/<action>

Parameters

  • <table>: Table name (required)
  • <action>: Action context (optional)

Response

Data attribute maps field names to their descriptions.

XDevMan/alumni:get

Returns a list of Alumni and their last-modified dates

Request

GET /api/xdevman/alumni/<year>

Parameters

  • <year>: The year of matriculation of the pupils

Response

GET /api/xdevman/alumni/2019
{
  "data": [
    {
      "pupil_id": "2240",
      "pupil_admin": "7623",
      "pupil_modify": "2019-11-11 16:25:54",
      "alumni_modify": "2020-01-02 16:04:04"
    },
    {
      "pupil_id": "1319",
      "pupil_admin": "7289",
      "pupil_modify": "2019-11-11 16:25:54",
      "alumni_modify": "2020-01-02 16:04:04"
    }
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

In each record, the internal ID and school-provided administration number are returned. There are two modification times because data for alumni is stored in two separate places (one from the historical pupil information, and another from the alumni-specific information).

XDevMan/currentpupils:get

Returns a list of current pupils and their list of modification dates.

Request

GET /api/xdevman/currentpupils

Parameters

  • none

Response

GET /api/xdevman/currentpupils
{
  "data": [
    {
      "pupil_id": "2240",
      "pupil_admin": "7623",
      "pupil_modify": "2019-11-11 16:25:54"
    },
    {
      "pupil_id": "1319",
      "pupil_admin": "7289",
      "pupil_modify": "2019-11-11 16:25:54"
    }
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

In each record, the internal ID and school-provided administration number are returned. There are two modification times because data for alumni is stored in two separate places (one from the historical pupil information, and another from the alumni-specific information).

XDevMan/leavers:get

Returns a list of Leavers and their last-modified dates. A leaver for a year is a person who was deregistered during the course of that year. It includes people from all grades.

Request

GET /api/xdevman/leavers/<year>

Parameters

  • <year>: The year of matriculation of the pupils

Response

GET /api/xdevman/leavers/2019
{
  "data": [
    {
      "pupil_id": "2240",
      "pupil_admin": "7623",
      "pupil_modify": "2019-11-11 16:25:54",
      "alumni_modify": "2020-01-02 16:04:04"
    },
    {
      "pupil_id": "1319",
      "pupil_admin": "7289",
      "pupil_modify": "2019-11-11 16:25:54",
      "alumni_modify": "2020-01-02 16:04:04"
    }
  ],
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

In each record, the internal ID and school-provided administration number are returned. There are two modification times because data for alumni is stored in two separate places (one from the historical pupil information, and another from the alumni-specific information).

XDevMan/alumnus:get

Returns the details of a single alumnus.

Request

GET /api/xdevman/alumnus/<pupil_id>

Parameters

  • <year>: The year of matriculation of the pupils

Response

GET /api/xdevman/alumnus/999
{
  "data": {
    "pupil_id": "999",
    "pupil_admin": "6727",
    "pupil_lastname": "xxx",
    "pupil_firstname": "xxx",
    "pupil_fullfirst": "xxx",
    "pupil_birth": "1994-08-xx",
    "pupil_final": "2012",
    "pupil_gender": "Female",
    "pupil_entry": "2010-07-12",
    "pupil_exit": "2012-12-31",
    "pupil_idnumber": "9408xxx",
    "pupil_population_id": "4",
    "pupil_language_id": "2",
    "pupil_language_other": "",
    "pupil_email": "",
    "pupil_email_personal": "",
    "pupil_prepschool": "xxx",
    "pupil_nationality": "South Africa",
    "pupil_boarder": "3",
    "alumni_title": "Miss",
    "alumni_marital_status": "",
    "alumni_maiden_name": "",
    "alumni_spouse_title": "",
    "alumni_spouse_firstname": "",
    "alumni_spouse_gender": null,
    "alumni_spouse_occupation": "",
    "alumni_date_married": "0000-00-00",
    "alumni_region": "",
    "alumni_district": "",
    "alumni_branch_id": null,
    "alumni_type_id": "1",
    "alumni_deceased": "No",
    "alumni_deceased_date": null,
    "alumni_workphone": "",
    "alumni_homephone": "(031) xxx 6xxx",
    "alumni_other": "",
    "alumni_reason_left": "",
    "alumni_exit_grade": "12",
    "alumni_previous_school": null,
    "alumni_qualification": "Senior Certificate",
    "family": {
      "families": [
        {
          "family_id": "873",
          "family_admin": "0",
          "family_primary_lastname": "xxx",
          "family_primary_firstname": "xxx",
          "family_primary_fullfirst": "xxx",
          "family_primary_initials": "X",
          "family_primary_title": "Mr",
          "family_primary_idnum": "651xxxx",
          "family_primary_gender": "Male",
          "family_primary_occupation": "xxx",
          "family_primary_employer": "xxx",
          "family_primary_workphone": "0315xxx",
          "family_primary_cell": "083xxx",
          "family_primary_birth": "1965-10-xx",
          "family_secondary_lastname": "xxx",
          "family_secondary_firstname": "xxx",
          "family_secondary_fullfirst": "xxx",
          "family_secondary_initials": "X",
          "family_secondary_title": "Mrs",
          "family_secondary_idnum": "6607xxx",
          "family_secondary_gender": "Female",
          "family_secondary_occupation": "xxx",
          "family_secondary_employer": "xxx",
          "family_secondary_workphone": "0315xxx",
          "family_secondary_cell": "083xxx",
          "family_secondary_birth": "1966-07-xx",
          "family_address_postal_1": "xxx",
          "family_address_postal_2": "xxx",
          "family_address_postal_suburb": "xxx",
          "family_address_postal_city": "",
          "family_address_postal_province": "",
          "family_address_postal_code": "xxx",
          "family_address_postal_country": "South Africa",
          "family_address_residential_1": "xxx",
          "family_address_residential_2": "xxx",
          "family_address_residential_suburb": "xxx",
          "family_address_residential_city": "",
          "family_address_residential_province": "",
          "family_address_residential_code": "",
          "family_address_residential_country": "xxx",
          "family_home_phone": "03150xxx",
          "family_home_fax": "03150xxx"
        }
      ],
      "email": [
        {
          "email_family_id": "873",
          "email_member": "primary",
          "email_address": "xxx@example.com"
        },
        {
          "email_family_id": "873",
          "email_member": "secondary",
          "email_address": "yyy@example.com"
        }
      ]
    }
  },
  "message": "",
  "response": {
    "error": "OK",
    "code": 200
  }
}

A record of a single alumnus is returned.

Specific Integration Requirements

Please see the Third Party Integration section in this documentation.