> For the complete documentation index, see [llms.txt](https://docs.stellic.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.stellic.com/stellic-partner-api/transfers/upload-an-official-transcript-for-a-student.md).

# Upload an official transcript for a student

Use this endpoint to submit a student's official transcript or Advanced Placement (AP) score report for transfer credit evaluation.

How to submit:

Send the document in the JSON request body using the data field:

* PDF transcript: Set type to "bitstream" and provide the PDF as a base64-encoded string.
* XML transcript: Set type to "xml" and provide the XML content.

For transcripts, `institution_id` is required. For AP score reports, you can omit it because the AP institution is selected automatically; if you send it, it must identify the AP institution.

What happens next?

A 200 response confirms the document was saved successfully. Stellic then reads the document and processes the transfer credits in the background.

## POST /transfers/transcript/upload/

>

```json
{"openapi":"3.0.0","info":{"title":"Stellic for Developers","version":"1.0"},"tags":[{"name":"Transfers"}],"servers":[{"url":"https://{institution}.stellic.com/partnerapi/v1","variables":{"institution":{"default":"{institution}","description":"Your institution's Stellic subdomain: the part before `.stellic.com` in the URL you use to sign in. It becomes the host in every request, as in `https://{institution}.stellic.com/partnerapi/v1/...`. Replace the `{institution}` placeholder with your subdomain before sending."}}}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Personal Access Token issued by your Stellic integration partner. Send it as `Authorization: Bearer <token>` on every request. One token per institution; do not share across environments."}}},"paths":{"/transfers/transcript/upload/":{"post":{"tags":["Transfers"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","data","student_username"],"oneOf":[{"required":["institution_id"],"properties":{"document_type":{"enum":["transcript"]}}},{"required":["document_type"],"properties":{"document_type":{"enum":["ap_score_report"]},"type":{"enum":["bitstream"]}}}],"properties":{"document_type":{"type":"string","enum":["transcript","ap_score_report"],"default":"transcript","description":"Kind of document being uploaded. Omit this field for a transcript, or send `ap_score_report` for an Advanced Placement (AP) score report."},"type":{"type":"string","enum":["bitstream","xml"],"description":"Format of the content in the `data` field. `bitstream` = base64-encoded PDF. `xml` = well-formed XML string using the supported transcript structure. AP score reports require `bitstream`."},"data":{"type":"string","description":"The document content. For `bitstream`, a base64-encoded PDF string (optionally wrapped in a `<fileContentBase64>` XML fragment). For `xml`, a well-formed XML document using the supported transcript structure, as a string. For an AP score report, the decoded content must begin with `%PDF-`."},"institution_id":{"type":"string","description":"Source institution or source campus identifier. Matched against IPEDS ID, CEEB ID, or external ID. When a source campus is supplied, the request is filed under its parent institution and the source campus is recorded. Required for transcripts. Optional for AP score reports, where the AP institution is selected automatically; if supplied, it must resolve to that institution. Null is rejected."},"student_username":{"type":"string","description":"Stellic username of the student the document belongs to. Must be non-empty. Archived students and test accounts are rejected."},"campus_id":{"type":"string","nullable":true,"description":"Optional. Target campus name, matched case-insensitively. At institutions with campus-based transfer credit, a non-empty value is required unless exactly one visible campus exists; that campus is selected automatically when the field is omitted, null, or empty. Elsewhere, a non-empty value returns 400; omission, null, and an empty string are accepted. At institutions without campus-based transfer credit, new requests use the student's assigned campus, or, if none is assigned, the first configured campus by ID, even if that campus is hidden. With campus-based transfer credit, re-uploads select only existing official requests for the resolved target campus, or create one for that campus if none exists. Without campus-based transfer credit, re-uploads select all existing official requests for that student and source institution without changing their target campuses. If more than one request would be selected, contact your Stellic Representative before uploading; only the first selected request receives the document contents."},"articulation_term":{"type":"object","description":"Optional. Applies a resolved articulation term to the affected request(s) after upload. Terms that cannot be resolved return 400 before the document is saved or a transfer request is changed.","properties":{"semester":{"type":"string","description":"Semester name, matched case-insensitively."},"year":{"type":"integer","minimum":1,"maximum":9999,"description":"Calendar year. Send an integer from 1 through 9999. The value is converted to an integer before range validation, so fractional numbers are truncated; numeric strings and booleans are also converted."}}}}}}}},"responses":{"200":{"description":"Document saved to the student's official transfer request and queued for reading and articulation in the background; this response is not a signal that credits have been granted. When transcript processing schedules cleanup, the request is deleted about two minutes later only if it has no saved or pending transcript data, has no files left to process, and all associated files, including previously removed files, were sent through this endpoint. A retained record of a manually uploaded file prevents deletion. A background XML conversion or transcript-processing failure does not schedule cleanup on that failure path, so an empty request can remain. When AP score-report parsing finds no exam results, the request returns to Draft and the report is removed from its active files; that failure does not schedule the two-minute request cleanup, so an empty request can remain.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"message":{"type":"string"}}}}}},"400":{"description":"Validation failure, returned as `{\"status\": \"error\", \"message\": \"<cause>\"}`. Body validation happens before the document is saved or a transfer request is changed. Causes: missing required field (`type`, `data`, `student_username`, or `institution_id` for a transcript), reported as `Required field(s) missing: <fields>`; invalid `document_type` (`Invalid document_type. Valid document types: ['transcript', 'ap_score_report']`); invalid `type` (`Invalid document type. Valid doc types: ['bitstream', 'xml']`); null or an unsupported type for `data` (`data must be a string.`); base64 decoding failure (`Invalid Base64 encoding: <detail>`); malformed XML (`Invalid XML format`); an AP score report whose decoded content does not begin with `%PDF-`, including an XML upload (`An ap_score_report must be a PDF.`); unknown, blank, or null `institution_id` (`Invalid Institution ID.`); an AP score report with an institution other than the AP institution (`institution_id must be the AP institution for an ap_score_report.`); blank or null `student_username` (`student_username must be a non-empty string.`); unknown username or test account (`No student exists with username: <username>`); archived student (`Student with username <username> is archived`); an `articulation_term` that cannot be resolved because its fields cannot be read or its year cannot be converted to an integer (`articulation_term must have semester (name) and integer year.`), its converted year is outside 1 through 9999 (`articulation_term year must be between 1 and 9999.`), or its semester is unknown (`Unknown semester: '<name>'.`); a parsed JSON body that is not an object or a JSON syntax error (`Request body must be a JSON object.`); invalid text encoding (the decoding error message); or a `campus_id` problem (`Campus personalization is not enabled; do not send campus_id.`, `Invalid Campus ID.`, or `campus_id is required when campus personalization is enabled.`)."},"401":{"description":"Missing or invalid Bearer token."},"403":{"description":"Your IP address isn't on the allowlist for this endpoint. Contact Stellic to add it; the response includes the `client_ip` Stellic saw.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"client_ip":{"type":"string"}}}}}},"500":{"description":"Unhandled server error, returned as `{\"status\": \"error\", \"message\": \"Something Went Wrong\"}`."}}}}}}
```

#### What happens after the call

* Transfer request created or updated: The document is added to the student's official transfer credit request, creating one if needed. Requests are categorized as exam credit (AP, IB, CLEP, etc.) or college credit. Institutions using campus-based transfer credit have separate requests for each campus.
* Credits processed automatically: Transcripts are read using OCR (PDF) or parsed (XML), while AP exam results are extracted. New courses or exam results are merged with existing ones and articulated in the background. Unlocked articulations are rebuilt, which changes their articulation\_id.
* If the document can't be read: When transcript processing schedules cleanup, the request is deleted after approximately two minutes if it has no saved or pending transcript data, has no files left to process, and all associated files, including previously removed files, were submitted through this endpoint. A retained record of a manually uploaded file prevents this deletion. For AP reports, the request returns to Draft, and the unreadable report is removed from active files. An empty request may remain. For XML, a background conversion or transcript-processing failure can leave the request in place without scheduling cleanup. Use the supported transcript structure, not just well-formed XML; ask your Stellic Representative for the supported format. Submit a readable document to try again.

#### Notes

* **Body validation happens before a file is attached or a transfer request is changed.** If validation fails, correct the rejected input and send the upload again.
* **`campus_id` is the campus name, case-insensitive, and only for institutions with campus-based transfer credit.** There, send a non-empty value unless exactly one visible campus exists; that campus is selected automatically when you omit it or send `null` or `""`. Everywhere else, leave it out or send `null` or `""`: a non-empty value returns a 400. At institutions without campus-based transfer credit, new requests use the student's assigned campus, or, if none is assigned, the first configured campus by ID, even if that campus is hidden. With campus-based transfer credit, re-uploads select only existing official requests for the resolved target campus, or create one for that campus if none exists. Without campus-based transfer credit, re-uploads select all existing official requests for that student and source institution without changing their target campuses. If more than one request would be selected, contact your Stellic Representative before uploading: only the first selected request receives the document contents.
* **For `bitstream`, send the base64 on its own or inside `<fileContentBase64>`.** The lowercase escapes `%2b`, `%2f`, and `%3d` are replaced for you; uppercase ones aren't. Padding is added when needed, but decoding can still fail. For transcripts, check that the decoded file is a PDF before sending; the upload does not check this.
* **Archived students and test accounts aren't accepted.** Send uploads for a non-archived student account that isn't a test account.
* **Usernames must match exactly.**
* **Locked articulations remain unchanged on a re-upload.** Hand-edited ones are kept only at institutions that preserve manual edits.
* To retain a specific source campus, send its identifier in `institution_id` on each transcript upload. A re-upload replaces the request's recorded source campus with the one you send; sending the parent institution's identifier clears it. This does not select your institution's target campus.

#### Related APIs

* [`GET /exports/articulated_courses`](/stellic-partner-api/exports/export-articulated-courses.md) to export the resulting transfer credit.
* [`GET /exports/equivalency_rules`](/stellic-partner-api/exports/export-equivalency-rules.md) for the rules used to articulate it.
