Errors

Branch on code, show message, never parse prose.

Failures return a JSON object under an error key.

1{
2 "error": {
3 "type": "invalid_request_error",
4 "code": "donor_not_found",
5 "message": "Donor 4217 was not found.",
6 "param": "donor_id",
7 "doc_url": null,
8 "recovery": "Confirm the identifier is correct and belongs to this institution, then retry.",
9 "details": null
10 }
11}
FieldUse it for
typeCoarse category, for deciding whether to retry at all.
codeBranch on this. Stable and machine-readable.
messageHuman-readable. Wording may change — never parse it.
paramThe field the error relates to, when it maps to one.
doc_urlLink to documentation for this error, when one exists.
recoveryPlain-language guidance you can surface to a person.
detailsPer-field failures on a validation error. Absent otherwise.

Types

typeMeaning
invalid_request_errorYour input: bad parameters, validation, not-found, conflict.
authentication_errorMissing or invalid credential.
rate_limit_errorThrottled. Back off and retry.
api_errorServer-side. Safe to retry.

Status codes

StatusWhen
400Malformed request, failed validation, or an unrecognised API key.
401Key missing or expired, or API access is not enabled for the institution.
403Key valid, but lacks the permission this endpoint needs.
404No such record belongs to this institution.
409Conflicts with existing data, or an idempotent retry is still in flight.
422Well-formed but unprocessable — including unrecognised fields.
429Rate limited. See Rate limits.

Codes

Branch on these. They are stable; new ones may be added.

codeStatus
validation_failed400
invalid_cursor400
unsupported_activity_type400
unauthorized401
invalid_credentials401
invalid_refresh_token401
donor_not_found404
scholarship_not_found404
award_cycle_not_found404
fund_not_found404
gift_not_found404
activity_not_found404
notification_not_found404
institution_not_found404
awarded_students_not_found404
email_already_exists409
idempotency_key_in_flight409
idempotency_key_request_mismatch422
rate_limit_exceeded429
internal_error500

Validation failures

A validation_failed error carries details, one entry per offending field. Show these against the fields they name rather than concatenating them into one message.

1{
2 "error": {
3 "type": "invalid_request_error",
4 "code": "validation_failed",
5 "message": "One or more validation rules failed. See details for specifics.",
6 "details": [
7 { "field": "amount", "message": "Amount is required." },
8 { "field": "gift_date", "message": "GiftDate is required." }
9 ]
10 }
11}

Unrecognised fields are rejected, not ignored

Send a field this API does not know and the request fails with the field named, rather than succeeding while quietly dropping your data. A typo in a field name is a loud error, which is the behaviour you want when the alternative is discovering months later that a column was never being saved.

One exception worth coding around

A 401 does not use the envelope above. It returns a plain-text reason. A client that assumes JSON on every error path will throw while handling the very case it was written for. Check the status before parsing, or guard the parse.

Every other status on this page returns the JSON error object.