List applications that have changed
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.
- First call only, name a starting point:
?updatedSince=2026-09-01T09:00:00+10:00. - Read
items. StorenextCursor. - If
hasMoreis true, call again immediately with?cursor=<nextCursor>. Repeat until it is false. - Later, poll again with the cursor you stored. An empty
itemsmeans 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.
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.
Authentication
Paste a Keycloak access token (no "Bearer " prefix)
Query parameters
The nextCursor from your previous response. Exclusive — it resumes after the last record you received. Mutually exclusive with updatedSince.
Records per page, 1–500. Defaults to 100.
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
The changed applications. Empty when nothing has changed, which is the normal steady state — not an error.
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.
