PayinferenceDocs
payinference.com

Errors

The API uses conventional HTTP status codes. Error bodies are JSON. Every response carries an x-request-id header; include it when reporting a problem.

Status codes#

Status Meaning Retry?
400 Validation failed; the request never reached the decision engine No. Fix the request
401 Missing or invalid API key No. Fix credentials
403 Key lacks a scope, is scoped to another merchant, or the workspace is inactive No. Fix key configuration
404 Unknown resource, for example an unknown decision_id on an outcome No
429 Rate limit exceeded Yes, after backing off
5xx Server error Your call: treat like a timeout and use your fallback path

Validation errors#

Requests are validated with strict schemas. The error echoes field paths and messages, never the submitted values:

json
{
  "error": "validation_error",
  "issues": [
    {
      "path": "transaction.amount",
      "code": "too_small",
      "message": "Number must be greater than 0"
    },
    {
      "path": "transaction.card_number",
      "code": "unrecognized_keys",
      "message": "Unrecognized key(s) in object: 'card_number'"
    }
  ]
}

Two validation behaviors worth knowing:

  • Unknown fields are rejected, not ignored. This is deliberate: it stops card data and PII from ever entering the system. If you see unrecognized_keys, remove the field rather than renaming it.
  • Amounts must be positive integers in minor units. 149.00 fails; 14900 passes.

Rate limit errors#

json
{ "error": "rate_limited", "limit_per_minute": 2000 }

See Rate limits for the windowing model and handling advice.

Auth and permission errors#

Standard NestJS error bodies with a human-readable message:

json
{ "statusCode": 403, "message": "API key is missing scopes: decision:write", "error": "Forbidden" }

The full list of authentication failures is in Authentication.

Handling errors in the payment path#

The important distinction is answers versus outages:

  • An HTTP error is an answer. The API received your request and rejected it. Retrying the same request will fail the same way. Do not retry 4xx responses.
  • A timeout or network error is an outage. You do not know what happened. Retry once if your budget allows, then fall back to your merchant-defined safe default. See Production integration.

The Node SDK encodes this: HTTP errors throw PayInferenceAPIError and are never retried; timeouts and network failures throw PayInferenceTimeoutError or PayInferenceNetworkError, are retried for reporting calls, and trigger the local fallback for decide() when one is configured.

ts
import {
  PayInferenceAPIError,
  PayInferenceTimeoutError,
  PayInferenceNetworkError,
  PayInferenceValidationError,
} from '@payinference/sdk-node';

try {
  const decision = await payinference.decide(params);
} catch (error) {
  if (error instanceof PayInferenceValidationError) {
    // Bad input; no request was made. error.issues lists field paths.
  } else if (error instanceof PayInferenceAPIError) {
    // The API answered with error.status and error.body. Do not retry.
  } else if (
    error instanceof PayInferenceTimeoutError ||
    error instanceof PayInferenceNetworkError
  ) {
    // Outage. Only reachable when no fallback is configured on the client.
  }
}

Debugging a failed request#

  1. Read issues[].path on validation errors; it names the exact field.
  2. Check the key mode and scopes on 401/403.
  3. Capture the x-request-id response header and the decision_id if one was returned.
  4. Look the decision up in the decision log (GET /v1/decisions/:decisionId or the dashboard) to see the matched rules, provider evaluations, and reason codes.