Skip to content
Last updated

Error Handling

The DeepCredentials API uses standard HTTP status codes and structured error responses.

Error response format

All error responses follow this structure:

codestringrequired

Machine-readable error code (e.g. not_found, unauthenticated). See table below.

messagestringrequired

Human-readable error description.

detailsobject

Optional structured data with additional context.

Error codes

CodeHTTP StatusDescriptionRetryable
ok200No error.
invalid_argument400Request validation failed (missing field, invalid format).No
unauthenticated401Missing, invalid, or expired credentials.No*
permission_denied403Valid credentials, but the token lacks the scope required by this endpoint.No
not_found404Resource does not exist or is not accessible to this credential.No
resource_exhausted429Rate limit exceeded.Yes (with backoff)
failed_precondition400Operation cannot be performed in the current state (e.g. an illegal credential-status transition).No
internal500Internal server error.Yes (with backoff)
unavailable503Service temporarily unavailable.Yes (with backoff)

* For expired Bearer tokens: re-authenticate against DeepCloud's SSO token endpoint to get a new access token (see Authentication — Service Users).

Authentication errors

Tokens are issued by DeepCloud's SSO realm, not by DeepCredentials. Token-endpoint failures (e.g. wrong client_secret, disabled service user, missing scope on the partner client) follow OAuth 2.0 standard error responses from Keycloak:

ErrorHTTP StatusDescription
invalid_request400Missing or unsupported parameter on the token call.
invalid_client401client_id or client_secret rejected by Keycloak.
invalid_grant400username / password rejected, or the service user is disabled.
unauthorized_client403The partner client isn't configured for the requested grant type or scope.

If the token endpoint succeeds but the API still rejects the request: the response will use the DeepCredentials error format above. The most common cause of a 403 from a B2B endpoint is a scope your partner client wasn't configured to grant — inspect the scope claim on the issued JWT (it lists what was actually granted, which may be a subset of what you requested).

Retry strategy

For retryable errors (429, 500, 503), use exponential backoff:

  1. Wait 1 second, then retry.
  2. If it fails again, wait 2 seconds.
  3. Double the wait time on each subsequent retry (4s, 8s, 16s...).
  4. Cap at 60 seconds maximum wait.
  5. Stop after 5 retries.

Add random jitter (±20%) to avoid thundering herd effects.

import time
import random

def retry_with_backoff(fn, max_retries=5):
    for attempt in range(max_retries):
        try:
            return fn()
        except RetryableError:
            if attempt == max_retries - 1:
                raise
            wait = min(60, (2 ** attempt)) * (0.8 + 0.4 * random.random())
            time.sleep(wait)
Do not retry client errors

Never retry 400, 401, 403, or 404 errors — these indicate a problem with your request that must be fixed in code.

Next steps