Every /v1 error is JSON. Fields you do not know may be added; pass over them.
Field
error
The code. Branch on it: a code does not change. Every code is listed below.
type
What to do, by status: one of the types below.
message
For a person: what went wrong and what to send instead. Its words may change, so do not match on them.
param
The field at fault, where the product knows which: loan, or start.amount inside an object. Not every error has one.
doc_url
The code’s entry on this page.
request_id
The same as the Request-Id header. Quote it to support.
problems
Where there is more than one thing wrong, each of them.
Some errors carry more: allowed on a 405, limit where a call takes only so many, resendAfter on a code asked for too soon.
Types
Type
Status
Do
invalid_request
400, 404, 405, 413, 422
Change the request. The message says what to send instead. Retry: not as it is.
authentication
401
Send a valid key. Retry: not with the same key.
permission
403
Use a key that may make this call. Retry: not with the same key.
conflict
409
Read the record again, or use a new idempotency key. Retry: after reading again.
rate_limit
429
Slow down. Retry: after Retry-After seconds.
api_error
500
Retry once. If it fails again, quote the request_id. Retry: once.
unavailable
502, 503, 504
Something this call needs did not answer. Retry: after Retry-After seconds, or with backoff.
A product’s own refusal
Some products answer a request they read but cannot act on in their own words: "ok": false and a list of problems — a ledger with an event it cannot place, a credit file missing a field. That answer carries the envelope too: error is refused, message is its first problem, and param names the field where the product knows it. Its own fields are kept beside them.
{
"error": "refused",
"type": "invalid_request",
"message": "The day to debit must be YYYY-MM-DD.",
"doc_url": "https://app.creditcresttechnologies.com.au/developers/errors#refused",
"ok": false,
"problems": ["The day to debit must be YYYY-MM-DD."],
"request_id": "req_7c1e2a9f04b3d568"
}
Request IDs
Every answer, success or not, has a Request-Id header. Log it beside your own reference for the call. When you write to hello@creditcresttechnologies.com.au about a call, quote it: it is how that one call is found.
Retrying safely
A GET changes nothing. Retry it freely.
Most POSTs are calculations on what you send — a statement read, a loan costed, a policy run — and keep nothing, so a retry gives the same answer. Each keyed call is counted, so send an Idempotency-Key with any you may retry.
An Idempotency-Key is 8 to 100 letters, digits, hyphens or underscores, such as a UUID. Sent again with the same request within 24 hours, the call runs again, its answer says Idempotent-Replayed: true, and it is counted and charged once.
import json, os, urllib.error, urllib.request
req = urllib.request.Request(
"https://app.creditcresttechnologies.com.au/v1/statement",
data=open("statement.csv", "rb").read(),
headers={
"Authorization": "Bearer " + os.environ["CREDITCREST_KEY"],
"Content-Type": "text/csv",
"Idempotency-Key": "read-2026-10-03-0001",
},
method="POST",
)
try:
with urllib.request.urlopen(req) as res:
print(res.status, res.headers.get("Idempotent-Replayed") or "first time")
except urllib.error.HTTPError as e:
print(json.load(e))
The same key with a different request is 409 idempotency_conflict. A call that was refused or failed does not use up its key: send the corrected request under it.
A key belongs to the API key that sent it. Only a fingerprint of it and of the request is kept, for 24 hours: never the body.
POST /v1/l/:tenant/applications keeps an application: under the same Idempotency-Key it returns the first answer, and is never kept twice.
A payment settled with POST /v1/l/:tenant/requests/:loanRef/settle goes on the account once, however many times it is sent.
On 429 wait Retry-After seconds. On 502, 503 or 504, wait Retry-After where it is given, or back off: 1, 2, 4, 8 seconds, with some randomness, then stop.
Every code
Keys
Code
Status
Means
Do
key_required
401
The call needs a key and none was sent.
Send "Authorization: Bearer <key>". A sandbox key is one call: POST /v1/keys/sandbox.
invalid_key
401
The key was not issued by Creditcrest, was altered, or is not whole.
Copy the key again, whole. Keys begin cc_test_ or cc_live_.
expired_key
401
The key is past its expiry date.
A sandbox key: get another. A live key: ask Creditcrest for a new one.
revoked_key
401
The key was withdrawn.
Ask Creditcrest for a new key.
out_of_scope
403
The key is not for this product.
The message lists the products the key covers. Ask for a key that covers this one.
wrong_lender
403
The key is another lender’s than the one in the address.
Use the lender’s own key. GET /v1/keys/me says whose a key is.
test_key
403
A test key cannot read or change a lender’s real records.
Use the lender’s live key.
live_key
409
A live key was sent to a lender whose records are not live yet.
Use a test key until the lender is live.
sandbox_only
422
The lender is not keeping real records yet, so a live key is refused.
Use a test key until the lender is live.
rate_limited
429
Too many calls this minute on this key, too many sandbox keys from one network address, or too many codes asked for from one network address.
Wait the Retry-After seconds, then spread the calls out. Limits are on the Authentication page.
keys_unavailable
503
Keys cannot be checked or issued here just now.
Retry shortly. If it persists, write to support with the request_id.
unauthorised
401
A provider’s webhook whose signature did not verify, or whose time was more than five minutes out.
For the identity provider: check its signing secret and its clock.
The request
Code
Status
Means
Do
bad_request
400
The request could not be read: a field is missing or malformed, or the body is not what the endpoint takes.
The message names the field and the shape to send. The endpoint’s reference lists what it takes.
not_found
404
No such address, or nothing is kept under that reference.
GET /v1 lists every endpoint. Check the reference.
method_not_allowed
405
The address exists, but not for this method.
Use a method listed in allowed (and in the Allow header).
too_large
413
The body is over the size this endpoint reads.
Send less in one call. The message says the limit.
too_many
413
More items than one call takes: events, applications or transactions.
Split them across calls. The message, and limit where given, say how many one call takes.
bad_day
422
"on" is not a day.
Send YYYY-MM-DD.
bad_period
422
"from" or "to" is not a day, or "from" is after "to".
Send both as YYYY-MM-DD, "from" first.
period_too_long
422
The period is longer than one report covers.
Ask for a shorter period. The message says the longest.
bad_month
400
month is not a calendar month.
Send month=YYYY-MM.
no_applications
422
The body has no applications.
The message shows the shape of one.
no_comparisons
422
The body has no comparisons.
Send the comparisons POST /v1/shadow returned.
refused
422, 429
The request was read, and what it asks cannot be done: problems, or the message, says why. A product’s own answer keeps its fields beside it, such as ok: false. As a 429, a code was asked for again too soon.
Correct what problems lists; param names the field where it is known. As a 429, wait until resendAfter.
invalid
422
The application has problems against the lender’s own checks.
Correct each item in problems and send it again.
too_many_codes
429
This mobile has been sent five codes today, or three in the last ten minutes, whoever asked. Nothing was sent or charged.
Wait the Retry-After seconds, or prove the email address instead.
texts_held
429
The lender’s texts for today have reached its daily ceiling, so this one was held: not sent, not charged. Creditcrest is alerted.
Use email codes until midnight in Sydney, or ask Creditcrest to raise the ceiling.
Retries
Code
Status
Means
Do
bad_idempotency_key
400
The Idempotency-Key header is not 8 to 100 letters, digits, hyphens or underscores.
Send a random id, such as a UUID.
idempotency_conflict
409
The Idempotency-Key was used before for a different request.
Use a new key for a new request. Reuse a key only to retry the same request.
conflict
409
Something else was recorded on the same loan at the same moment.
Read the loan again, then retry.
Products
Code
Status
Means
Do
policy_unreadable
422
The credit policy text has problems.
problems lists each line and what is wrong with it.
policy_cannot_run
422
The policy was read but cannot run on this application.
The message says which rule and why.
not_evidence
422
The body is not signing evidence Creditcrest issued.
Send the evidence exactly as it was returned.
not_valid
422
The evidence’s seal does not check, so no certificate is made.
verification says what failed. Send the evidence unaltered.
not_signed
404
There is no signature on file for this loan.
Check the loan reference, or have the contract signed first.
bad_name
422
The staff member’s name cannot be used.
Send their full name, as it should appear on every change they make.
bad_role
422
The role is not one the console has.
The message lists the roles.
bad_email
422
The work email cannot be used.
The message says why.
not_on_list
404
Nobody active on the lender’s staff list has that work email.
Add them to the staff list first, or send a name and role.
The lender’s set-up
Code
Status
Means
Do
not_open
503
This lender is not taking applications yet.
The lender finishes going live first.
shadow_mode
409
The lender’s configuration is in shadow, so nothing reaches an applicant.
Turn shadow off to go live.
records_unreachable
503
The lender’s own records service did not answer. Nothing was run.
Check the records service is up, then retry.
no_session_secret
503
This lender keeps real records and the server has no session secret for staff sign-in.
Write to support with the request_id.
usage_unavailable
503
Usage cannot be read just now.
Retry after Retry-After seconds.
Creditcrest’s side
Code
Status
Means
Do
internal_error
500
The request failed on Creditcrest’s side.
Retry once. If it fails again, write to support with the request_id.
Creditcrest’s own: 18 codes from the invoicing addresses, which take Creditcrest’s admin token
Code
Status
Means
Do
admin_token_required
401
An invoicing address needs Creditcrest’s admin token.
Not for lenders.
not_configured
503
The invoice run is off on this server.
Set USAGE_ADMIN_TOKEN.
bad_lender
400
lender is not a lender id.
Send a lender id.
bad_format
400
format is not json or pdf.
Send format=json or format=pdf.
bad_issued
400
issued is not a day the invoice can be dated.
The message says why.
bad_adjustment
400
adjustment is not the number of a note.
Send 1, 2, 3 …
bad_body
400
The adjustment’s reason is missing or too long.
The message says the limit.
bad_rows
400
The rows to put back are not as usageNotKept logged them.
Send {"rows": [...]} from the log.
already_issued
409
The invoice is issued and is not dated again.
Ask without issued.
issued_meanwhile
409
Another note was issued at the same time.
Look at the month again before issuing another.
not_issued
404, 409
No invoice was issued for that month.
GET the invoice to issue it.
not_kept
503
A final invoice or note could not be kept, so it is not shown.
Retry after Retry-After seconds.
nothing_to_adjust
409
Made again, the month agrees with the invoice as issued.
Nothing to do.
remake_not_final
409
Made again, the month is not final.
Fix what problems lists first.
issued_invoice_differs
409
Made again, the month differs from the invoice as issued.
Issue an adjustment note.
not_as_issued
500
An issued invoice no longer reads back as it was issued.
The message says what differs. Do not issue another until it is understood.
invoice_unavailable
503
The lender’s configuration, usage or issued invoices could not be read.
Retry shortly.
gst_status_differs
409
The invoice was issued under a different GST status than the month has now.