API reference

Errors

Every error from the Credicorp API uses one envelope and a conventional HTTP status. Read the machine-readable code to branch your logic and the message for logs — never parse the prose. Quote the request_id when you contact support.

The API uses standard HTTP status codes: 2xx for success, 4xx when something about the request is wrong (and retrying unchanged won't help), and 5xx for the rare problem on our side. Failures relating to lending outcomes — a declined decision, a returned payment — are not API errors: those succeed with 2xx and carry the outcome in the resource body.

The error envelope

All errors share this shape. The top-level key is always error.

json
{
  "error": {
    "type": "invalid_request_error",
    "code": "parameter_missing",
    "message": "Missing required parameter: amount_pence.",
    "param": "amount_pence",
    "doc_url": "https://dev.credicorp.co.uk/api-reference/apply.html#create",
    "request_id": "req_7Hs2bV9k"
  }
}
FieldTypeDescription
typestringalwaysBroad category — one of the five types below. Branch on this first.
codestringalwaysStable, machine-readable identifier for the specific error. Your code should switch on this.
messagestringalwaysHuman-readable explanation for logs. Wording may change — never parse it.
paramstringoptThe offending field, for validation errors. Dotted path, e.g. business.company_number.
doc_urlstringoptDeep link to the relevant documentation section.
request_idstringalwaysUnique ID for the request. Also returned in the Credicorp-Request-Id response header. Quote it to support.

The request_id is on every response, success or failure, via the Credicorp-Request-Id header. Log it alongside your own correlation ID so a single line in your logs maps to a single line in ours.

Error types

The type tells you, at a glance, whose problem it is and whether a retry could ever help.

typeHTTPMeaning
authentication_error401The token is missing, malformed, expired or revoked.
permission_error403Authenticated, but the key lacks the required scope for this resource.
invalid_request_error400/404/409The request is malformed, references something that doesn't exist, or conflicts with current state.
rate_limit_error429Too many requests. Back off and retry — see Rate limits.
api_error500/503Something went wrong on our end. Safe to retry idempotent requests with back-off.

HTTP status map

The full set of statuses the API returns and how your client should treat each.

StatusWhenRetry?
200 OKRequest succeeded.
201 CreatedA resource was created (e.g. an application).
202 AcceptedAccepted for async processing (e.g. a disbursement queued).
400 Bad RequestMalformed JSON or a failed validation rule.No — fix the request.
401 UnauthorizedNo valid credential.No — refresh the token.
403 ForbiddenValid credential, insufficient scope.No — request the scope.
404 Not FoundUnknown ID, or hidden by your permissions.No.
409 ConflictState conflict, or an Idempotency-Key reused with a different body.No — reconcile first.
422 UnprocessableWell-formed but semantically invalid (e.g. term outside 3–60 months).No — correct the value.
429 Too Many RequestsRate limit exceeded. Honour Retry-After.Yes — with back-off.
500 Server ErrorAn unexpected fault on our side.Yes — idempotent only.
503 UnavailableTemporary maintenance or overload.Yes — back-off; check status.

Common error codes

Switch on code for predictable handling. These are stable identifiers — new codes may be added, so treat an unknown code as a generic failure of its type.

codetypeWhat it means
parameter_missinginvalid_request_errorA required field was omitted; see param.
parameter_invalidinvalid_request_errorA field is the wrong type or fails a format rule.
resource_missinginvalid_request_errorNo object exists for the supplied ID.
idempotency_conflictinvalid_request_errorAn Idempotency-Key was reused with a different payload.
company_not_foundinvalid_request_errorThe Companies House number did not resolve to an active entity.
amount_below_minimuminvalid_request_errorRequested principal is under the £1,000 floor.
term_out_of_rangeinvalid_request_errorterm_months is outside the 3–60 month range.
mandate_not_activeinvalid_request_errorA payment was attempted against a revoked or pending mandate.
token_expiredauthentication_errorThe bearer token has passed its expiry; refresh it.
token_revokedauthentication_errorThe credential was revoked in the dashboard.
insufficient_scopepermission_errorThe key is not granted the scope this endpoint needs.
rate_limit_exceededrate_limit_errorRequest rate over the limit; see Retry-After.
internal_errorapi_errorAn unexpected fault. Retry idempotent calls; then contact support with the request_id.

A validation error in full

Sending a request that omits a required field returns 400 with param populated:

bash
curl -i https://api.credicorp.co.uk/partner/v1/applications \
  -H "Authorization: Bearer $TOKEN" \
  -d '{ "term_months": 12 }'

HTTP/2 400
Credicorp-Request-Id: req_7Hs2bV9k
Content-Type: application/json

{
  "error": {
    "type": "invalid_request_error",
    "code": "parameter_missing",
    "message": "Missing required parameter: amount_pence.",
    "param": "amount_pence",
    "request_id": "req_7Hs2bV9k"
  }
}

Handling errors in the SDKs

The SDKs raise typed exceptions that mirror the type field, each exposing code, param and requestId. Catch the specific exception you can recover from and let the rest bubble.

php
use Credicorp\Exception\{InvalidRequestException, RateLimitException, ApiErrorException};

try {
    $app = $cc->applications->create($payload);
} catch (InvalidRequestException $e) {
    // $e->getCode() === 'parameter_missing', $e->getParam() === 'amount_pence'
    log_warning($e->getMessage(), $e->getRequestId());
} catch (RateLimitException $e) {
    sleep($e->getRetryAfter());   // then retry
} catch (ApiErrorException $e) {
    // transient — safe to retry idempotent calls with back-off
}
node
try {
  const app = await cc.applications.create(payload);
} catch (err) {
  switch (err.type) {
    case 'invalid_request_error':
      console.warn(err.code, err.param, err.requestId);
      break;
    case 'rate_limit_error':
      await sleep(err.retryAfter * 1000); // retry
      break;
    default:
      throw err;
  }
}
python
import credicorp

try:
    app = cc.applications.create(**payload)
except credicorp.error.InvalidRequestError as e:
    log.warning("%s on %s (%s)", e.code, e.param, e.request_id)
except credicorp.error.RateLimitError as e:
    time.sleep(e.retry_after)   # then retry
except credicorp.error.APIError:
    pass  # transient — retry idempotent calls with back-off

Retry only idempotent requests on 5xx and 429, and always send the same Idempotency-Key so a retried POST can't double-create. See the idempotency guide.