# Upgrading to v2

## 1. Adoption of Collections vs. Resources

In **v2**, our API follows RESTful principles more strictly by differentiating between **Collections** and **Resources.** A **Collection** represents a group of items whereas a **Resource** represents a specific item.

In **v1**, the API structure included the **School ID** as the last segment of the URL, and when retrieving a specific item. The **ID** was passed either as a **query parameter** or was included in the **request body**.

In **v2**, the API structure follows a more RESTful approach:

* **Resources** now have their **ID passed in the URL** (e.g., `/learners/{learner_id}`).
* **Collections** exclude the ID and are retrieved using a general endpoint (e.g., `/learners`).

#### **Request Example:**

<table><thead><tr><th width="180.9842529296875">Operation</th><th width="257.958740234375">v1 Endpoint</th><th>v2 Endpoint </th></tr></thead><tbody><tr><td>Get all learners</td><td><code>/learners/{{SCHOOL_ID}}</code></td><td><code>/learners</code></td></tr><tr><td>Get a specific learner</td><td><code>/learners/{{SCHOOL_ID}}?learner_id=123</code></td><td><code>/learners/123</code></td></tr></tbody></table>

This change also impacts the response payload structure:

* In **v1**, all responses that contained data were returned as an array, even when fetching a single item.
* In **v2**, the response format aligns with RESTful design:
  * A **Resource** request returns a single object.
  * A **Collection** request returns an array, wrapped inside a `data` object to support additional metadata (see introduction of Pagination below).&#x20;

#### Response Example:

{% tabs %}
{% tab title="Resource" %} <mark style="color:green;">`GET`</mark> `/learners/1` <- *Notice the Resource ID is now part of the URL*

```json
{
    "learner_id": 1,
    "first_name": "John",
    "last_name": "Smith",
    "gender": "M",
    "grade": "7",
    "debtor_code": "1001",
    "parent1_id": 40,
    "parent2_id": 41,
    "accountable_person_id": 40
}
```

{% endtab %}

{% tab title="Collection" %} <mark style="color:green;">`GET`</mark> `/learners`

```json
[
    "data": [
        {
            "learner_id": 1,
            "first_name": "John",
            "last_name": "Smith",
            "gender": "M",
            "grade": "7",
            "debtor_code": "1001",
            "parent1_id": 40,
            "parent2_id": 41,
            "accountable_person_id": 40
        },
        {
            "learner_id": 2,
            "first_name": "Jane",
            "last_name": "Doe",
            "gender": "F",
            "grade": "5",
            "debtor_code": "1001",
            "parent1_id": 40,
            "parent2_id": 41,
            "accountable_person_id": 40
        }
    ],
    "meta": {
        ...
    }
]
```

{% endtab %}
{% endtabs %}

## 2. School ID Moved to Request Headers

In light of the above changes to the API, the **School ID** moved to the **request headers**. This is to accommodate the changes for the adoption of a collection versus a resource design (see above).

**In example:**

```bash
curl 'https://integrate.d6plus.co.za/api/v2/learners/1' \
     --header 'HTTP-X-USERNAME: yourusername' \
     --header 'HTTP-X-PASSWORD: yourpassword' \
     --header 'HTTP-X-SCHOOLID: 1234'
```

## 3. Pagination Introduced

Version 2 of the Integrate API adopted pagination to help improve server performance and reduce response times. We've adopted the **cursor-based pagination** strategy, which uses an opaque string to mark the starting point for the next set of items.

The following **query parameters** allows you to control pagination:

<table><thead><tr><th width="155.7427978515625">Name</th><th width="92.05712890625">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>cursor</code></td><td>String</td><td>To retrieve the next group of items</td></tr><tr><td><code>limit</code></td><td>Integer</td><td>To override the default limit of records returned (up to the <code>max_allowed_limit</code> provided in the response metadata).</td></tr><tr><td><code>reverse_order</code></td><td>Boolean</td><td>To sort the results in descending order (useful for fetching the latest records first).</td></tr></tbody></table>

The **response payload** now includes a `meta` object containing pagination-related data.

* `next_cursor`  – The cursor to use for retrieving the next set of items. If no further data is available, this field is omitted.
* `limit`  – The number of records returned
* `max_allowed_limit`  – The maximum number of records that can be requested per page

#### Response Example:

```json
{
    "data": [
        ...
    ],
    "meta": {
        "limit": 10,
        "max_allowed_limit": 50,
        "next_cursor": "eyJpZCI6MTA4MDMsIl9iYWNrd2FyZCI6ZmFsc2V9"
    }
}
```

## 4. Correct Type-Casting in Response Body

In **v1**, all response fields were returned as **strings**, regardless of their actual data type. This required clients to manually parse numbers, booleans, and other data types.

In **v2**, all fields in the response body are now **properly type-casted** to their correct data types, reducing processing overhead and improving API consistency.

{% tabs %}
{% tab title="v2" %}

```json
{
  "data": [    
    {
      "school_id": 1234,
      "name": "Greenwood High",
      "students_count": 450,
      "email_address": "admin@greenwoodhigh.co.za",
      "has_after_school_center": "Yes"
    },
    {
      "school_id": 1340,
      "name": "Riverside Academy",
      "students_count": 520,
      "email_address": null,
      "has_after_school_center": "No"
    }
  ]
}
```

{% endtab %}

{% tab title="v1" %}

```json
[
  {
    "school_id": "1234",
    "name": "Greenwood High",
    "students_count": "450",
    "email_address": "admin@greenwoodhigh.co.za",
    "has_after_school_center": "Yes"
  },
  {
    "school_id": "1340",
    "name": "Riverside Academy",
    "students_count": "520",
    "email_address": "",
    "has_after_school_center": "No"
  }
]
```

{% endtab %}
{% endtabs %}

## 5. Success Responses Updated

The **success** **response** format has been updated to a more standardized format.

The response fields are as follows:

* **`success`** – Indicates whether the request was successful.
* **`message`** – A success confirmation message.
* **`data`** – An object that contains the ID of the item that has been created. Additional fields of the created item may be included in the data object if necessary.

#### Create Request Example:

{% tabs %}
{% tab title="v2 Create Response" %} <mark style="color:orange;">`POST`</mark> `/v1/notes`

**Status Code:** <mark style="color:green;background-color:green;">`201 Created`</mark>

**Response Body:**

```json
{
    "success": true,
    "message": "Note created successfully",
    "data": {
        "note_id": 2543
    }
}
```

{% endtab %}

{% tab title="v1 Create Response" %} <mark style="color:orange;">`POST`</mark> `/v1/notes/{{SCHOOL_ID}}`

**Status Code:** <mark style="color:green;background-color:green;">`200 OK`</mark>

**Response Body:**

```json
{
    "note_id": "2545"
}
```

{% endtab %}
{% endtabs %}

#### Delete Request Example:

{% tabs %}
{% tab title="v2 Delete Response" %} <mark style="color:red;">`DELETE`</mark> `/v1/notes/2545`

**Status Code:** <mark style="color:green;background-color:green;">`200 OK`</mark>

**Response Body:**

```json
{
    "success": true,
    "message": "Note deleted successfully"
}
```

{% endtab %}

{% tab title="v1 Delete Response" %} <mark style="color:red;">`DELETE`</mark> `/v1/notes/{{SCHOOL_ID}}?note_id=2545`

**Status Code:** <mark style="color:green;background-color:green;">`200 OK`</mark>

**Response Body:**

```json
{
    "status": "Deleted"
}
```

{% endtab %}
{% endtabs %}

## 6. Error responses updated

Similar to the success responses, the **error response** format has also been updated to provide a more consistent format across the API.

The response fields are as follows:

* `success` – Indicates whether the request was successful.
* `message` – A success confirmation message.

In the event of a user input validation failure, the following will be included in the response body:

* `validation_errors` – A list of fields and the validation error message

Not Found Error Example:

{% tabs %}
{% tab title="v2 Not Found Error" %}
**Status Code:** <mark style="color:red;background-color:green;">`404 Not Found`</mark>

**Response Body:**

```json
{
    "success": false,
    "message": "The note does not exist."
}
```

{% endtab %}

{% tab title="v1 Not Found Error" %}
**Status Code:** <mark style="color:red;background-color:green;">`404 Not Found`</mark>

**Response Body:**

```json
{
    "error": "Not Found",
    "error_description": "The note does not exist."
}
```

{% endtab %}
{% endtabs %}

#### Validation Error Response Example:

{% tabs %}
{% tab title="v2 Validation Error" %}
**Status Code:** <mark style="color:red;background-color:green;">`400 Bad Request`</mark>

**Response Body:**

```json
{
    "success": false,
    "message": "Validation Failed",
    "validation_errors": {
        "note_id": "The note_id is invalid",
        "date": "The Date is not valid date format. Expected format is 'Y-m-d'."
    }
}
```

{% endtab %}

{% tab title="v1 Validation Error" %}
**Status Code:** <mark style="color:red;background-color:green;">`400 Bad Request`</mark>

**Response Body:**

```json
{
    "error": "Validation failed",
    "error_description": {
        "note_id": "The note_id is invalid",
        "date": "The Date is not valid date format. Expected format is 'Y-m-d'."
    }
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
To ensure backward compatibility, some existing errors that were previously returned in v1 may still use the old response format. However, all newly introduced errors follow the updated structure, making it easier to handle and interpret responses moving forward.
{% endhint %}

## 7. Changes to Individual API Calls

In addition to the changes mentioned above, this section outlines specific updates to API endpoints and fields introduced in v2. These updates align the API more closely with RESTful principles.

<details>

<summary>Settings</summary>

## 1. Get Client Integrations

The API call named **Settings/Clients** has been renamed to **Settings/ClientIntegrations,** additionally the school ID does not form part of the URL anymore but moved to a **query parameter**.

### **Endpoint:**

**Old:**

```http
GET /v1/settings/clients(/{school_id})
```

**New:**

```http
GET /v2/settings/clientintegrations(?school_id={school_id},...)
```

### **Response Body:**

`school_login_id` changed to `school_id`

```json
[
    {
        "school_id": 1000, // school_login_id -> school_id
        "school_name": "d6+ Primary School",
        "admin_email_address": "support@d6plus.co.za",
        ...
    },
    ...
]
```

## 2. Update Client Integration

Similar to the "Get" call, the "Update" call was renamed from **Settings/Clients** to **Settings/ClientIntegrations**. The school ID does not form part of the URL anymore but moved to the **request body**. The request method also changed from PATCH to **POST**.

### **Endpoint:**

**Old:**

```http
PATCH /v1/settings/clients/{school_id}
```

**New:**

```
POST /v2/settings/clientintegrations
```

### **Request Body:**

**Old:**

```json
{
    "api_type_id": 8,
    "state": 1
}
```

**New:**

```json
{
    "school_id": 1219, // <- now part of the request body
    "api_type_id": 8,
    "state": 1
}
```

</details>

<details>

<summary>Finance+</summary>

## 1. Get Learner Parent Info

The API call to get **Learner Parent Info** has been renamed to **Learners**.

### **Endpoint:**&#x20;

**Old:**

<pre class="language-http"><code class="lang-http"><strong>GET /v1/finplus/debtmanagement/learnerparentinfo/{school_id}(?learner_id=123)
</strong></code></pre>

**New:**

```http
GET /v2/finplus/debtmanagement/learners(/{learner_id})
```

## 2. Get School Debtors

The API call to get **School Debtors** has been renamed to **Accountable Persons**.

### Endpoint:

**Old:**

```
GET /v1/finplus/debtmanagement/schooldebtors/{school_id}
(?accountable_person_id=123)
```

**New:**

```
GET /v2/finplus/debtmanagement/accountablepersons(/{accountable_person_id})
```

</details>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://apidocs.d6plus.co.za/v2/getting-started/upgrading-to-v2.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
