> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs-unsw-v6.advance-uac.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs-unsw-v6.advance-uac.com/_mcp/server.

# List applications that have changed

GET https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes

Every application of yours that has changed, oldest change first, each one carrying its
credit decision alongside it. This is how you keep your own records in step without polling
applications one at a time.

## The loop

Between polls you keep **one thing**: the cursor.

1. **First call only**, name a starting point: `?updatedSince=2026-09-01T09:00:00+10:00`.
2. Read `items`. Store `nextCursor`.
3. If `hasMore` is true, call again **immediately** with `?cursor=<nextCursor>`. Repeat until
   it is false.
4. Later, poll again with the cursor you stored. An empty `items` means nothing has changed —
   that is the normal steady state, not an error. Keep your cursor and try again later.

Sending both `updatedSince` and `cursor` is a 400. A cursor already carries a position, and
silently preferring one would let a client with broken cursor handling appear to work while
skipping records on every poll.

## Each item is two things

`application` is exactly what GET /institution/applications/\{id} returns. `outcome` is
exactly what GET /institution/applications/\{id}/outcome returns. Detecting a change and
reading what changed is therefore one call, not three.

`outcome` is **null** when the application has never been assessed. That is different from an
outcome saying no credit was awarded — see [Credit outcomes](/credit-outcomes).

## What it gives you, and what it does not

The feed carries **current state, not history**. An application that changes five times
appears in five polls, each time with its latest state; there is no event log and no replay.
So deduplicate on `application.id` and keep the newest copy.

There is **no retention limit**. Any historical `updatedSince` works, because the feed queries
live records rather than a log. If your own database is ever lost, replay the whole history
by passing an old timestamp.

Two things it cannot tell you:

* **A deletion.** A deleted application simply stops appearing. If you need to detect
  removals, reconcile periodically with a full replay.
* **What specifically changed.** You get the new state, not a diff. Compare against your own
  copy if you need to know which field moved.

## Timestamps must carry an offset

`updatedSince` requires a full ISO-8601 timestamp with an explicit offset. A bare date is
rejected rather than assumed, because the assumption is measurably wrong: on real data
`2026-08-11T00:00:00+10:00` matched 8 records and `2026-08-11T00:00:00Z` matched 7, because
`Z` is 10am in Sydney. A caller asking for "the 11th" would silently lose a morning and never
find out. After the first call the cursor handles this for you.

## Ordering and the short delay

Records come back in the order they changed, and the cursor is a position in that order — so
paging is stable even while the feed is being written to.

The feed deliberately stops about **30 seconds short of now**. A record's timestamp is taken
when the change is made but only becomes visible when the transaction commits, so a change
stamped slightly earlier can appear slightly later. Reading right up to the present moment
would let such a record slip behind an advancing cursor and be **lost permanently**. The
window trades a few seconds of latency for not losing records.

A change you made seconds ago will therefore not be in the current page. It will be in the
next one.

Reference: https://docs-unsw-v6.advance-uac.com/unsw-advance-institution-api/applications/list-applications-that-have-changed

## Authentication

- `Authorization` header (bearer token, required) — Paste a Keycloak access token (no "Bearer " prefix)

## Servers

- `https://unsw-v6-dev.advance-uac.com/institution-api` (Dev, default)
- `https://unsw-v6-test.advance-uac.com/institution-api` (Test)

## Request

### Query parameters

- `cursor` (string, optional) — The `nextCursor` from your previous response. Exclusive — it resumes after the last record you received. Mutually exclusive with `updatedSince`.
- `size` (integer, optional) — Records per page, 1–500. Defaults to 100.
- `updatedSince` (string, optional) — Full ISO-8601 timestamp WITH an offset, e.g. `2026-09-01T09:00:00+10:00`. Inclusive. Use on your first call only; a bare date is rejected. Mutually exclusive with `cursor`.

## Response

### 200

A page of changed applications, oldest first.

- `items` (list of ChangedApplication, optional) — The changed applications. Empty when nothing has changed, which is the normal steady state — not an error.
- `nextCursor` (string, optional) — Pass this back as `cursor` on your next call. Null only when the page is empty, in which case keep the cursor you already have.
- `hasMore` (boolean, optional) — True when more changed records are already waiting. Call again straight away rather than waiting for your next poll.

## Errors

### 400 Bad Request Error

Both `cursor` and `updatedSince` were sent, an `updatedSince` without a timezone offset, an unusable `cursor`, or a `size` outside 1–500.

- `status` (integer, optional) — Repeats the HTTP status code.
- `error` (string, optional) — What went wrong, in a form safe to show a developer.

## Types

### ChangedApplication

One changed application and its credit decision — exactly what GET /institution/applications/\{id} and GET .../outcome would return, together, so detecting a change and reading it is one call rather than three.

- `application` (ApplicationView, optional) — An application's current status, data and qualifications.
- `outcome` (Outcome, optional) — The credit decision. **Null when the application has never been assessed** — distinct from an outcome reporting no credit.

### ApplicationView

An application's current status, data and qualifications.

- `id` (string, optional)
- `applicantId` (string, optional)
- `programCode` (string, optional)
- `year` (integer, optional)
- `stream` (string, optional)
- `intakeCode` (string, optional) — Your own code for the intake the applicant is starting, e.g. "5269" for Term 3 2026. Optional, but worth sending: our officers work applications in intake order, and one with no intake cannot be prioritised against the rest. Send the code rather than the name. These are YOUR term codes, loaded from the intake schedule you supply us, so a code you use is a code we hold; one we do not recognise is refused with a 400 naming it.
- `intake` (string, optional) — The intake's name, e.g. "Term 3 2026". Null when no intake is set.
- `status` (string, optional) — Application status: RECEIVED, READY, PROCESSING, WITHDRAWN or FAILED.
- `statusDetail` (string, optional) — Failure detail when status is FAILED; null otherwise.
- `workflowStatus` (string, optional) — Assessment workflow status once processed (e.g. DECIDED, CREDIT_TEAM_REVIEW); null while RECEIVED.
- `qualifications` (list of QualificationView, optional)
- `sourceName` (string, optional) — The system this record was fed from, in your own vocabulary. Free text, and required whenever you send a sourceRef.
- `sourceRef` (string, optional) — Your own unique id for this application, e.g. an application number. Unique per `sourceName`.
- `sources` (list of ApplicationSourceReference, optional) — Your own references for this record, one per system you keep it in. A person or an application known by a different id in SITS than elsewhere carries both. Optional. `sourceName` and `sourceRef` still work exactly as before and count as the FIRST entry here, so nothing you have already built needs to change. Send both forms and they are combined, with duplicates collapsed. Order matters: the first entry is the one echoed back as `sourceRef`, and the one shown in lists and in the change feed.
- `specialisations` (list of ApplicationSpecialisation, optional) — The specialisations this application is for, in the order they were chosen. Empty when there are none.
- `submittedAt` (datetime, optional)
- `updatedAt` (datetime, optional)

### Outcome

The credit decision on an application, as it finally stands.

- `applicationId` (string, optional)
- `status` (string, optional) — Intake status: RECEIVED, READY, PROCESSING, WITHDRAWN or FAILED.
- `statusDetail` (string, optional) — Why intake failed, when status is FAILED. Null otherwise.
- `workflowStatus` (string, optional) — Assessment workflow status code; null until the application is assessed.
- `workflowStatusLabel` (string, optional) — That status in words, e.g. "Decided".
- `assessed` (boolean, optional) — Whether an assessment has run at all. False means no credit has been considered yet, not that none was awarded.
- `finalOutcome` (boolean, optional) — Whether the workflow has reached an end state. While false the credit below is provisional and can still change.
- `assessedAt` (datetime, optional) — When assessment started; null until it does.
- `completedAt` (datetime, optional) — When the workflow reached its end state; null while it is still running.
- `totalCreditUoc` (integer, optional) — Total credit awarded, in units of credit. The sum of `uoc` below, so rejected credit contributes nothing.
- `awaitingAuthority` (boolean, optional) — Whether any credit below is waiting on an academic authority. That credit IS counted in `totalCreditUoc` — it stands unless the authority refuses it — so while this is true the total can still fall. `finalOutcome` is false whenever it is true. Read `authorityState` on each credit to see which ones.
- `credits` (list of Credit, optional) — Every piece of credit considered, including any rejected.

### QualificationView

A qualification as stored.

- `id` (string, optional)
- `type` (string, optional) — tertiary | subject | work_experience.
- `parentId` (string, optional) — The qualification this one sits under — a subject's degree. Null for a top-level qualification.
- `data` (map from string to any, optional) — The type-specific fields, consolidated across every source that has reported this qualification.
- `documentCount` (integer, optional) — How many supporting documents are attached, so you can tell at a glance whether evidence has been uploaded. Counts confirmed uploads only; list them with GET /institution/qualifications/\{id}/documents.

### ApplicationSourceReference

One of your own references for this record: the system it came from, and its id there.

- `sourceName` (string, optional) — The system this record was fed from, in your own vocabulary. Free text, and required whenever you send a sourceRef.
- `sourceRef` (string, optional) — Your own unique id for this application, e.g. an application number. Unique per `sourceName`.

### ApplicationSpecialisation

One specialisation an application is for. `code` and `year` are what the application recorded; `name` and `type` are the catalogue's own words and are null if the catalogue no longer holds that specialisation.

- `code` (string, optional)
- `year` (integer, optional) — Handbook year, the application's own year.
- `name` (string, optional)
- `type` (string, optional) — Major, Minor, Honours, Specialisation or Research.

### Credit

One piece of credit: what earned it, what it counts towards, and what it is worth.

- `id` (string, optional) — This one piece of credit. Unique within the assessment.
- `decisionId` (string, optional) — The DECISION this credit belongs to. Several credits share it when one decision awarded several units — a mapping with three targets produces three credits with one `decisionId`. Group on it to show what was decided together.
- `origin` (string, optional) — `assessed` — produced by the assessment pipeline. `manual` — awarded by an officer outright.
- `status` (string, optional) — `granted` — it counts. `rejected` — an officer struck it out; it stays on the record with its reason and counts 0. `exempt` — the requirement is met without credit, also 0.
- `provisional` (boolean, optional) — The credit is approved and counted, but the applicant does not receive it until they have completed the further study described in `note` — typically after a year. `status` stays `granted` because that is what it is; this says when it lands. It does not affect `totalCreditUoc` or `finalOutcome`.
- `uoc` (integer, optional) — Units of credit awarded, after any officer override. 0 when rejected or exempt.
- `assessedUoc` (integer, optional) — What the pipeline assessed, present ONLY when an officer changed it. Its presence is how you tell an override from a plain grant.
- `authorityState` (string, optional) — Where this credit stands with an academic authority, when the credit team escalated it to one. `awaiting` — sent and not answered; it counts towards the total and could still be refused. `confirmed` — the authority agreed; it stands. `refused` — the authority rejected it; `uoc` is 0 and `assessedUoc` says what it would have been. NULL is the normal case: nobody was asked, because auto-matched credit is approved and the credit team decides it.
- `mechanism` (string, optional) — How it was earned: articulation, precedent, rpl, employment, or manual.
- `category` (string, optional) — For block credit, what kind: core, elective or employment. Null for credit against a named unit.
- `targetUnitCode` (string, optional) — The unit the credit counts towards. Null for block credit, which is granted against a category rather than a named unit.
- `sources` (list of CreditSource, optional) — The prior study or experience that earned it.
- `reason` (string, optional) — Why the pipeline awarded it, in its own words.
- `note` (string, optional) — The officer's note, when they recorded one.
- `decidedAt` (datetime, optional) — When it was decided — the officer's decision if there was one, otherwise when the pipeline awarded it.

### CreditSource

Prior study or experience that earned credit.

- `type` (string, optional) — What kind of thing it is: `subject` or `course` for a unit of study, `tertiary` for a whole qualification, `work_experience` for a job.
- `code` (string, optional) — Its code, as supplied.
- `name` (string, optional) — Its name, where one was recorded. Present when the credit came from a mapping, which stores names alongside codes; absent on the rules-based paths, which carry codes only.

## Examples

### A page with more to follow

**Response**

```json
{
  "items": [
    {
      "application": {
        "id": "9c1f4d3e-6b2a-4f18-9c77-2b5a1e0d8f42",
        "applicantId": "5e8b2a71-3c94-4d06-8f21-9a7c4e1b3d50",
        "programCode": "3778",
        "year": 2026,
        "stream": "DOMESTIC_FP",
        "status": "PROCESSING",
        "workflowStatus": "DECIDED",
        "qualifications": [
          {
            "id": "b71c9e35-8f24-4a17-9d60-3e5b8c1a7f92",
            "type": "tertiary",
            "data": {
              "code": "C09067",
              "completedYear": 2024,
              "institution": "University of Technology Sydney",
              "name": "Bachelor of Computer Science"
            },
            "documentCount": 1
          }
        ],
        "sourceName": "SITS",
        "sourceRef": "APP-2026-00123",
        "submittedAt": "2026-08-24T09:02:11.400+10:00",
        "updatedAt": "2026-09-01T09:05:00.000+10:00"
      },
      "outcome": {
        "applicationId": "9c1f4d3e-6b2a-4f18-9c77-2b5a1e0d8f42",
        "status": "PROCESSING",
        "workflowStatus": "DECIDED",
        "workflowStatusLabel": "Decided",
        "assessed": true,
        "finalOutcome": true,
        "assessedAt": "2026-08-24T09:15:02.113+10:00",
        "completedAt": "2026-09-01T09:05:00.000+10:00",
        "totalCreditUoc": 6,
        "credits": [
          {
            "id": "0b6e5c21-9a44-4f0e-93b1-77c2d5a10e64",
            "origin": "assessed",
            "status": "granted",
            "uoc": 6,
            "mechanism": "precedent",
            "targetUnitCode": "COMP1511",
            "sources": [
              {
                "type": "subject",
                "code": "31251"
              }
            ],
            "reason": "Matched credit mapping 4f2b (exchange)",
            "decidedAt": "2026-08-24T09:15:04.882+10:00"
          }
        ]
      }
    },
    {
      "application": {
        "id": "2f7a1c88-5d43-4e91-b206-8c3f0a5e9d71",
        "applicantId": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
        "programCode": "8429",
        "year": 2026,
        "stream": "DOMESTIC_FP",
        "status": "RECEIVED",
        "qualifications": [],
        "sourceName": "SITS",
        "sourceRef": "APP-2026-00124",
        "submittedAt": "2026-09-01T09:06:30.000+10:00",
        "updatedAt": "2026-09-01T09:06:30.000+10:00"
      }
    }
  ],
  "nextCursor": "MjAyNi0wOS0wMVQwOTowNjozMFsxMDowMHwyZjdhMWM4OC01ZDQzLTRlOTEtYjIwNi04YzNmMGE1ZTlkNzE",
  "hasMore": true
}
```

**SDK Code**

```python A page with more to follow
import requests

url = "https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes"

headers = {"Authorization": "Bearer <token>"}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript A page with more to follow
const url = 'https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go A page with more to follow
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby A page with more to follow
require 'uri'
require 'net/http'

url = URI("https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java A page with more to follow
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php A page with more to follow
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp A page with more to follow
using RestSharp;

var client = new RestClient("https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift A page with more to follow
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Caught up

**Response**

```json
{
  "items": [],
  "hasMore": false
}
```

**SDK Code**

```python Caught up
import requests

url = "https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes"

headers = {"Authorization": "Bearer <token>"}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript Caught up
const url = 'https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Caught up
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Caught up
require 'uri'
require 'net/http'

url = URI("https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java Caught up
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php Caught up
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp Caught up
using RestSharp;

var client = new RestClient("https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift Caught up
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://unsw-v6-dev.advance-uac.com/institution-api/institution/applications/changes")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```