Skip to navigation

List applications that have changed

View as Markdown

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.

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

AuthorizationBearer

Paste a Keycloak access token (no "Bearer " prefix)

Query parameters

cursorstringOptional

The nextCursor from your previous response. Exclusive — it resumes after the last record you received. Mutually exclusive with updatedSince.

sizeintegerOptional

Records per page, 1–500. Defaults to 100.

updatedSincestringOptional

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

A page of changed applications, oldest first.
itemslist of objectsOptional

The changed applications. Empty when nothing has changed, which is the normal steady state — not an error.

nextCursorstringOptional

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.

hasMorebooleanOptional
True when more changed records are already waiting. Call again straight away rather than waiting for your next poll.

Errors

400
Bad Request Error