Errors

📘

Please reference the API Reference which will indicate which endpoints throw which specific MuralServiceExceptions. The API Reference should be used as the single source of truth for all MuralServiceException response body definitions.

The Mural API can throw various errors. If it is expected that an error from the Mural API should be handled gracefully, an error will be serialized to the http response as a MuralServiceException with the following shape:

interface MuralServiceException {
  errorInstanceId: string,
  name: MURAL_ERROR_NAME, // identifier of the specific error type, see below
  message: string
  params: map<string, any> // params defined by the specific error type, see below
}

We have a number of specific MuralServiceException types, which are outlined below:

SignedAgreementRequiredException

Definition

interface SignedAgreementRequiredException extends MuralServiceException {
  name: "SignedAgreementRequiredException",
  message: "End user must accept Terms of Service",
  params: {
    organizationId: string 
  }
}

Expected next steps:

You should generate a new Terms of Service link using the hosted TOS link endpoint and display that to your user such that they can sign the Terms of Service.

TransactionInProgressError

Definition

  interface TransactionInProgressError extends MuralServiceException {
    name: "TransactionInProgressError";
    message: "Another transaction is being processed for this account. Please retry in a few seconds.";
    httpStatusCode: 409; // Conflict
    params: {
      safeAddress: string;
    };
  }

Expected next steps:

This error indicates that another transaction is currently being processed for the same account. You should:

  • Wait and retry - Wait a few seconds and retry the request. The in-flight transaction should complete shortly.

  • Implement exponential backoff - For automated systems, implement retry logic with exponential backoff (e.g., 1s, 2s, 4s delays).

  • Check transaction status - Query the pending transaction's status to confirm it completes before retrying.

    This is a transient error and does not indicate a problem with your request. The same request should succeed once the in-progress transaction completes.

PayoutQuoteExpiredException

Definition

interface PayoutQuoteExpiredException extends MuralServiceException {
  name: "PayoutQuoteExpiredException";
  message: "This payout request had an expired quote. The exchange rate has been automatically updated for the effected payouts. Please retry the payout to execute the payout request with the updated payouts.";
  params: {
    expiredQuotes: ExpiredQuote[];
  };
}

interface ExpiredQuote {
  payoutId: string;
  fiatCurrencyCode: string;
  previousRate: number; // represents 1 USD equivalent in the destination currency
  newRate: number; // represents 1 USD equivalent in the destination currency
  previousFiatAmount: number;
  newFiatAmount: number;
}

Expected next steps:

You can immediately turn around and execute the Payout Request again, or you can show this information to your user for them to take the next step.


PayinMinimumNotMetError

Definition:

export class PayinMinimumNotMetError extends MuralServiceException {
  name = 'PayinMinimumNotMetError';
  message: `Payin amount less fees must be greater than ${params.minimumFiatAmount.fiatAmount} ${params.minimumFiatAmount.fiatCurrencyCode}. Net payout amount provided was ${(params.providedFiatAmount.fiatAmount - params.fees.fiatAmount)} ${params.providedFiatAmount.fiatCurrencyCode}`;
  params: {
    minimumFiatAmount: FiatAmount;
    providedFiatAmount: FiatAmount;
    fees: FiatAmount;
    exchangeRate?: number;
  };
}

export class FiatAmount {
  fiatAmount: number;
  fiatCurrencyCode: string;
}

Expected next steps:

You should make a new payin request where the payin amount less fees is greater than the minimum fiat amount.


PayoutMinimumNotMetError

Definition:

export class PayoutMinimumNotMetError extends MuralServiceException {
  name = 'PayoutMinimumNotMetError';
  message: `Payout amount less fees must be greater than ${params.minimumFiatAmount.fiatAmount} ${params.minimumFiatAmount.fiatCurrencyCode}. Net payout amount provided was ${(params.providedFiatAmount.fiatAmount - params.fees.fiatAmount)} ${params.providedFiatAmount.fiatCurrencyCode}`;
  params: {
    minimumFiatAmount: FiatAmount;
    providedFiatAmount: FiatAmount;
    fees: FiatAmount;
    exchangeRate?: number;
  };
}

export class FiatAmount {
  fiatAmount: number;
  fiatCurrencyCode: string;
}

Expected next steps:

You should make a new payout request where the payout amount less fees is greater than the minimum fiat amount.


InsufficientBalanceError

Definition

interface InsufficientBalanceError extends MuralServiceException {
  name: "InsufficientBalanceError";
  message: "Insufficient balance for transaction. Required: {requiredAmount} {availableBalance.tokenSymbol}, Available: {availableBalance.amount} {availableBalance.tokenSymbol}";
  params: {
    requiredAmount: string;
    availableBalance: {
      amount: string;
      tokenSymbol: string;
      blockchain: string;
    }
    payoutId: string;
  };
}

Expected next steps:

This error indicates that the account does not have sufficient token balance to complete the requested transaction. You should either:

  • Deposit additional funds to the account to meet the required amount
  • Reduce the transaction amount to be within the available balance
  • Check that you are using the correct account with sufficient funds

PayoutMethodError

Definition

interface PayoutMethodError extends MuralServiceException {
    name: "PayoutMethodError";
    message: "Payout method {payoutMethodId} is in an error state. Until remediated, any payouts using this payout method will fail. Please use a different payout method or contact support for more information.";
    params: {
      payoutMethodId: string;
      payoutMethodErrorReason: PayoutMethodErrorReason;
    };
  }

  enum PayoutMethodErrorReason {
    DISABLED_BY_PROVIDER = "DISABLED_BY_PROVIDER"
  }

Expected next steps:

This error indicates that the payout method is currently unavailable and cannot be used to process payouts. The payoutMethodErrorReason field explains why:

  • DISABLED_BY_PROVIDER: The payment provider has deactivated the external account associated with this payout method. This typically occurs when the provider detects an issue with the bank account details or compliance status.

You should either:

  • Use a different payout method for the recipient

  • Create a new payout method with updated bank account details

  • Contact support to understand why the provider disabled the account and what steps are needed to remediate


PayoutComplianceValidationFailedError

Definition

interface PayoutComplianceValidationFailedError extends MuralServiceException {
  name: "PayoutComplianceValidationFailedError";
  message: "Payout request failed compliance validation. Please supply the required supporting details.";
  params: {
    complianceFailures: ComplianceValidationPayoutFailure[];
  };
}

interface ComplianceValidationPayoutFailure {
  payoutIndex: number;
  failureReasons: PayoutComplianceValidationFailureReason[];
  failedChecks: PayoutComplianceValidationCheckType[];
}

enum PayoutComplianceValidationFailureReason {
  MISSING_SUPPORTING_DOCUMENT = "MISSING_SUPPORTING_DOCUMENT",
  MISSING_TRANSFER_PURPOSE = "MISSING_TRANSFER_PURPOSE",
  MAX_TRANSFER_VOLUME_LIMIT_EXCEEDED = "MAX_TRANSFER_VOLUME_LIMIT_EXCEEDED"
}

enum PayoutComplianceValidationCheckType {
  PAYMENT_VALUE_THRESHOLD = "PAYMENT_VALUE_THRESHOLD",
  AGGREGATE_THIRTY_DAY_PAYOUT_VOLUME = "AGGREGATE_THIRTY_DAY_PAYOUT_VOLUME",
  INTERNAL_VALIDATION = "INTERNAL_VALIDATION"
}

Expected next steps:

This error indicates that one or more payouts in the request require additional compliance information. The complianceFailures array identifies which payouts failed (by payoutIndex) and why. You should:

  • Check the failureReasons for each failed payout to determine what is missing
  • If MISSING_SUPPORTING_DOCUMENT — include a supportingDocument (base64 data URI) in the payout's supportingDetails
  • If MISSING_TRANSFER_PURPOSE — include a payoutPurpose in the payout's supportingDetails
  • If MAX_TRANSFER_VOLUME_LIMIT_EXCEEDED — the recipient has exceeded the maximum transfer volume limit. Contact support for further guidance.

The failedChecks field indicates which compliance rule triggered the requirement (e.g., single payment threshold, 30-day aggregate volume).

AdditionalCounterpartyInformationRequired

Definition

interface AdditionalCounterpartyInformationRequired extends MuralServiceException {
  name: "AdditionalCounterpartyInformationRequired";
  message: "Additional counterparty information is required for counterparty {counterpartyId}: {missingFields}";
  httpStatusCode: 400; // Bad Request
  params: {
    counterpartyId: string;
    missingFields: string[];
  };
}

Expected next steps:

This error indicates that the counterparty is missing one or more fields required for the payout method type you are trying to attach. You should either:

  • Update the counterparty with the missing fields and retry
  • Use a different counterparty that already has the required fields
  • Use a different payout method type that does not require those fields

AdditionalRecipientInformationRequired

Definition

interface AdditionalRecipientInformationRequired extends MuralServiceException {
  name: "AdditionalRecipientInformationRequired";
  message: "Additional recipient information is required for the following payouts: payouts[{i}]: {missingFields}; ...";
  httpStatusCode: 400; // Bad Request
  params: {
    failures: RecipientValidationFailure[];
  };
}

interface RecipientValidationFailure {
  payoutIndex: number;
  details: MissingInlineRecipientInformation | MissingCounterpartyInformation;
}

interface MissingInlineRecipientInformation {
  type: "inlineRecipient";
  missingFields: string[];
}

interface MissingCounterpartyInformation {
  type: "counterparty";
  counterpartyId: string;
  payoutMethodId: string;
  missingFields: string[];
}

Expected next steps:

This error indicates that one or more payouts in the request are missing fields required for their destination. The failures array identifies which payouts failed (by payoutIndex) and what is missing. For each failure:

  • If details.type === "inlineRecipient" — populate the missing fields on payouts[payoutIndex].recipientInfo and resubmit
  • If details.type === "counterparty" — update the saved counterparty (details.counterpartyId) with the missing fields and resubmit

All failing payouts are returned in a single response so you can correct every recipient in one pass.

RateLimitExceededError

Definition

  interface RateLimitExceededError extends MuralServiceException {
    name: "RateLimitExceededError";
    message: "Too many requests. Please retry shortly.";
    httpStatusCode: 429; // Too Many Requests
    params: {
      retryAfterSeconds: number;
    };
  }

Expected next steps:

This error indicates that you have exceeded the request rate limit. You should:

  • Wait before retrying - Wait params.retryAfterSeconds, which is also sent in the standard Retry-After header.
  • Read the rate limit headers - Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, so you can slow down before you are rejected rather than after.
  • Replace polling with webhooks - Most rate limiting comes from polling for state that Mural already pushes. See Webhooks.

See Rate Limits for how the limit is counted, including how it applies to requests made on behalf of a child organization.

CapabilityNotEnabledException

Definition

interface CapabilityNotEnabledException extends MuralServiceException {
  name: 'CapabilityNotEnabledException';
  message: "You don't have access to this capability. Contact support to request access.";
  httpStatusCode: 403; // Forbidden
  params: {
    fiatCurrencyCode?: string; // omitted when the currency has no public API representation
    rampDirection: RampDirection;
    reason: CapabilityNotEnabledReason;
  };
}

enum RampDirection {
  ON_RAMP = 'ON_RAMP',
  OFF_RAMP = 'OFF_RAMP',
}

enum CapabilityNotEnabledReason {
  NOT_GRANTED = 'NOT_GRANTED',
  IN_REVIEW = 'IN_REVIEW',
  DISABLED = 'DISABLED',
}

Expected next steps:

This error indicates that your organization cannot use the requested currency and direction. The reason field explains why:

  • NOT_GRANTED: The capability is not part of your organization's configuration. Contact support to request access.
  • IN_REVIEW: The capability was requested and is still being provisioned. Wait for provisioning to complete, or contact support if it stays in review.
  • DISABLED: The capability was disabled for your organization. Contact support to restore access.

A 403 response can carry either this error or SignedAgreementRequiredException. Read the name field to tell them apart. Do not assume that a 403 means the Terms of Service are unsigned.


Did this page help you?