Skip to content

Errors

PaymentError subclasses exported from packages/core/src/errors.ts via @paykernel/core.

Updated View as Markdown

All classes below are defined in packages/core/src/errors.ts and re-exported from packages/core/src/index.ts as @paykernel/core. Catch PaymentError for the family, then branch with instanceof.

import {
  PaymentError,
  InvalidWebhookError,
  InvalidRequestError,
  NetworkError,
  OperationNotSupportedError,
} from "@paykernel/core";

PaymentError.statusCode is metadata on the error object. It is not the HTTP status your webhook route should return. HTTP mapping lives in @paykernel/integration-http (mapInboxOutcome), not in @paykernel/webhooks and not in these class defaults.

Published as part of @paykernel/core 1.0.0.

Classes (errors.tsindex.ts)

Class code Default statusCode When it is thrown
PaymentError caller-supplied 500 Base class. new PaymentError(message, code, statusCode?)
PaymentAbortedError PAYMENT_ABORTED 400 Before-hook abort or caller AbortSignal on operation params. Not a provider timeout (those map to NetworkError)
GatewayNotConfiguredError GATEWAY_NOT_CONFIGURED 400 Named gateway is missing from the client/registry
OperationNotSupportedError OPERATION_NOT_SUPPORTED 400 Gateway lacks the method or capability (capability?, claimedSupport? on the options bag)
InvalidWebhookError INVALID_WEBHOOK 403 Webhook verification failed (bad signature, missing secret, provider rejected the transmission)
GatewayApiError GATEWAY_API_ERROR 502 Provider HTTP/API call failed. gatewayName, optional rawError
CardDeclinedError CARD_DECLINED 402 Issuer declined the card. Optional rawError
InsufficientFundsError INSUFFICIENT_FUNDS 402 Insufficient funds. Optional rawError
AuthenticationError AUTHENTICATION_FAILED 401 Auth failed (3DS, wrong CVV/expiry, and similar). Optional rawError
RateLimitError RATE_LIMIT_EXCEEDED 429 Gateway rate limit. Optional retryAfterSeconds from Retry-After
ResourceNotFoundError RESOURCE_NOT_FOUND 404 Requested gateway resource does not exist. Optional rawError
InvalidRequestError INVALID_REQUEST 400 Validation failed upstream or at the gateway. Optional validationErrors
NetworkError NETWORK_ERROR 503 Transport failure. See afterProviderSubmit below

Type-only companion (not a class): OperationNotSupportedErrorOptions (capability?, claimedSupport?, message?). Two-arg new OperationNotSupportedError(name, op) remains valid.

NetworkError.afterProviderSubmit

try {
  await client.createPayment(params);
} catch (err) {
  if (err instanceof NetworkError && err.afterProviderSubmit) {
    // Provider may already have accepted the POST.
    // Lookup + decideReconciliationPolicy only.
    // Do NOT createPayment again. Do NOT auto-route a second gateway.
  }
  throw err;
}

afterProviderSubmit is true when the provider may already have accepted a mutating request (timeout / drop / 5xx after POST). Callers must reconcile, not retry as a fresh failure. Preflight auth and GET failures stay false.

On the happy path of create/capture/refund/void, post-submit timeout / drop / 5xx typically becomes outcome: "indeterminate" + reconciliationRequired: true rather than a thrown NetworkError. That is still not a decline. Do not createPayment again. See outcomes.

Webhook verify vs parse

Failure Class Meaning
Signature / secret / authenticity InvalidWebhookError Forgery or misconfiguration. Map to a 4xx in your HTTP adapter (mapInboxOutcome / invalid_webhook)
Authenticated payload, bad shape InvalidRequestError Parse failed after verify. Not a forged webhook. Treat as server/data-shape — typically retryable 5xx via inbox handler_failed

handleWebhook does not set HTTP status. Never fulfill in onWebhookVerified. Claim via @paykernel/webhooks, then fulfill only when the rematched event is payment.succeeded or capture.completed and payment.status === "paid", bound to gatewayPaymentId.

try {
  const event = await client.handleWebhook("stripe", rawBody, signature);
  // verify + parse only — do not fulfill here
} catch (err) {
  if (err instanceof InvalidWebhookError) {
    // authenticity failure
  } else if (err instanceof InvalidRequestError) {
    // parse / shape failure after verify
  } else {
    throw err;
  }
}

MoneyAmountError extends InvalidRequestError. It is defined in packages/core/src/utils/money.ts and is a runtime export of @paykernel/core (kind: MoneyFailureKind). Branch on kind, not English messages. See money.

Catch pattern

import { PaymentError, isPaidOutcome } from "@paykernel/core";

try {
  const result = await client.createPayment(params);
  if (isPaidOutcome(result)) {
    // paid settlement only
  } else if (result.outcome === "indeterminate" || result.reconciliationRequired) {
    // do not retry createPayment
  }
} catch (err) {
  if (err instanceof PaymentError) {
    // err.code, err.statusCode (object metadata, not webhook HTTP)
  }
  throw err;
}

Full runtime catalog: core API.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close