> 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/credit-outcomes/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. # Credit outcomes Submitting an application starts a credit assessment. The result is a list of credit, each piece saying what prior study earned it, what it counts towards, and what it is worth. Read it from: ``` GET /institution/applications/{id}/outcome ``` > **Warning** > > Applications submitted through this API are not yet picked up for assessment automatically. > They stay at `assessed: false` until that is released. > > Build your polling against this endpoint now — it will start returning outcomes with no > change on your side. ## Read `assessed` before anything else The trap in this response is that two completely different situations produce an identical `credits` list. Compare these: **`No assessment has run`** ```json title="No assessment has run" { "status": "RECEIVED", "assessed": false, "finalOutcome": false, "totalCreditUoc": 0, "credits": [] } ``` **`Assessed, and awarded nothing`** ```json title="Assessed, and awarded nothing" { "status": "PROCESSING", "assessed": true, "finalOutcome": true, "totalCreditUoc": 0, "credits": [] } ``` Both have no credit and a total of zero. `assessed` is the only thing separating "we have not looked yet" from "we looked, and none of this prior study earns credit here" — which is the difference between waiting and telling the applicant. | Field | Meaning | | -------------- | ---------------------------------------------------------------------------------- | | `assessed` | An assessment has run. While `false`, an empty `credits` list means nothing yet. | | `finalOutcome` | The workflow has reached an end state. While `false`, the credit below can change. | So: poll until `finalOutcome` is `true`. An application can sit at `assessed: true` with `finalOutcome: false` for days while a credit officer reviews it, and the figures move during that time. ## What one piece of credit looks like ```json { "id": "0b6e5c21-9a44-4f0e-93b1-77c2d5a10e64", "origin": "assessed", "status": "granted", "uoc": 6, "assessedUoc": null, "mechanism": "precedent", "category": null, "targetUnitCode": "COMP1511", "sources": [{ "type": "subject", "code": "31251", "name": null }], "reason": "Matched credit mapping 4f2b (exchange)", "note": null, "decidedAt": "2026-08-24T09:15:04.882+10:00" } ``` `sources` is **everything** that earned it. One decision can require several subjects together — a credit mapping with four source courses, or an internal rule that consumes two subjects for one unit — and every one of them is listed, each with its own `type` so a subject, a whole qualification and a period of employment stay distinguishable. `targetUnitCode` is what it counts towards, and is `null` for block credit — granted against a `category` (`core`, `elective`, `employment`) rather than a named unit. ## One decision can award several units `id` identifies one piece of credit. **`decisionId` identifies the decision it came from**, and several credits share one when a single decision awarded several units: ```json [ { "id": "0b6e5c21…", "decisionId": "7c2e91a4…", "targetUnitCode": "COMM6106", "uoc": 6 }, { "id": "3d9a7e08…", "decisionId": "7c2e91a4…", "targetUnitCode": "COMM6112", "uoc": 6 } ] ``` That is one decision worth 12 UOC across two units, not two independent awards — and both carry the same four `sources`. Group on `decisionId` if you want to show what was decided together; ignore it and sum `uoc` if you only need the total. Credits that stand alone have a `decisionId` of their own. > **Note** > > Because a decision's sources apply to the whole decision, they are repeated on each of its > credits. Four sources across two units means the same four entries appear twice — that is > intentional, not duplication in the underlying record. `origin` says where the credit came from: | `origin` | Meaning | | ---------- | ------------------------------------------------------------------------------- | | `assessed` | Produced by the assessment pipeline from a rule or a credit mapping. | | `manual` | Awarded outright by a credit officer. No `reason`, because no rule produced it. | ## `uoc` is always what the credit is worth now A credit officer can overrule the pipeline: reject a grant, re-price it, or mark it exempt. `uoc` already reflects that, so `totalCreditUoc` is a plain sum of the column and you never have to do per-status arithmetic. | `status` | `uoc` | Meaning | | ---------- | ---------------- | ----------------------------------------------------------------------------- | | `granted` | what it is worth | It counts. See `provisional` below for credit that counts but is conditional. | | `rejected` | `0` | An officer struck it out. `note` says why. | | `exempt` | `0` | The requirement is met without credit points being awarded. | **Rejected credit stays in the list.** Dropping it would leave you unable to tell "this was never considered" from "this was considered and refused", which is the question an applicant asks first. ### Credit the applicant does not have yet `provisional: true` marks credit that is approved but conditional: the applicant receives it once they have completed the further study `note` describes, typically a year later. It is **granted credit**. `status` is `granted`, `uoc` is what it is worth, and it counts towards `totalCreditUoc` — because it stands unless the condition is not met. What is conditional is *when* the applicant gets it, not whether. ```json { "targetUnitCode": "MATH6306", "status": "granted", "uoc": 6, "provisional": true, "note": "On completion of MATH1131 with a credit average, expected end of 2027." } ``` So if you are telling an applicant what credit they hold today, read `provisional` and say so. If you are reconciling totals, ignore it — the number is already right. > **Note** > > `provisional` is a separate field rather than a fourth `status` value on purpose: this > credit reads as `granted` to anything that was written before the field existed, which is > what it has always been. `assessedUoc` appears **only when an officer changed the number**, and carries what the pipeline originally said. Its presence is how you tell an override from an ordinary grant: ```json { "status": "rejected", "uoc": 0, "assessedUoc": 6, "note": "Content overlaps the precedent credit already granted for COMP1511." } ``` Six units were assessed; none are awarded. If you are reconciling against your own records, `assessedUoc` is what explains the difference. > **Note** > > `decidedAt` follows the same idea: it is when the *officer* decided, if one did, and > otherwise when the pipeline awarded it. ## What the application record shows `GET /institution/applications/{id}` returns the application and its `qualifications` — what we hold, in the field names you sent, validated against the schemas at `GET /institution/qualification-types`. It carries no credit and never changes to reflect an outcome. The credit decision only ever lives on the outcome endpoint above. If you integrated against an earlier version of this API, note that the `applicationData` object has been removed from that response: it was an internal projection of the same qualifications, renamed into our assessment engine's vocabulary, and it told you nothing `qualifications` does not. ## Polling 1. Submit the application and keep the `id`. 2. Poll `GET /institution/applications/{id}/outcome`. 3. Stop when `finalOutcome` is `true`. Assessment is not instant and it is not uniform — one application clears in seconds, another waits on a person. Poll on the order of minutes rather than seconds, and treat `assessed: true` with `finalOutcome: false` as progress rather than an answer. > Reading the credit decision on an application, and knowing when it is final