Skip to main content

Error Responses

Overview

When a Business API request fails, the response body is a JSON Error object with a consistent shape across every endpoint. The Type field tells you the category of failure and maps to the HTTP status code:

TypeHTTPWhen it happens
InvalidMessage400The request is malformed or a field fails validation.
Unauthorized401The API key is missing, invalid, or expired, or request signing failed.
Forbidden403A policy or compliance rule blocks the action.
ResourceNotFound404A referenced resource does not exist.
InsufficientBalance402The account balance is below the requested amount.
Unexpected500An unexpected server-side error occurred.

Error envelope

Every error response includes these fields:

FieldDescription
TypeError category: InvalidMessage, Forbidden, InsufficientBalance, ResourceNotFound, Unauthorized, or Unexpected
ActionInternal action name for the operation that failed (for example create customer, withdraw)
DetailHuman-readable summary of the failure
InstanceUnique ID for this occurrence — use it to correlate a failure with server logs when contacting support
RequestExtensionField-level validation details (see below)
DenyExtensionPolicy or compliance denial details (see below)

RequestExtension

Field-level problems are returned in RequestExtension.Body as an array of items:

FieldDescription
FieldDot path to the request field (for example CustomerID, Form.BankDetails.AccountNumber)
ReasonWhy the field failed — see the values below
DescriptionWhat failed and, where possible, how to fix it

Reason is one of:

ReasonMeaning
SchemaValidationValue fails the JSON Schema or a business rule (wrong type, length, pattern, required).
IntegrityValidationCross-field or state conflict (for example a referenced resource does not exist, or a form session expired).
NotSupportedThe value is well-formed but not supported for this operation (for example an IBAN that does not support SEPA transfers).
SelfReferenceThe request points back at the caller in a way that is not allowed (for example withdrawing to your own deposit address).

DenyExtension

Policy denials include Reason (InsufficientPermissions, Compliance, AccountStatus, or VerificationRequired), Description, and the Principal / Resource involved. These appear when an actor is not permitted to use a resource — for example a currency not enabled for your profile, a customer in compliance review, or a channel blocked for a destination country.

Form field errors

Some endpoints accept a Form object for payment or onboarding data. Those fields are validated against a JSON Schema — either a channel form schema for payouts or an onboarding schema for KYC.

The set of possible form field errors is not fixed globally. It depends on the channel, payment method, country, provider, and schema version. The same field can produce different Description text on different channels.

To reduce opaque server-side failures:

  1. Retrieve the relevant schema before submitting (for example GET /channels/{ChannelID}/form for payout forms).
  2. Validate Form client-side against that JSON Schema.
  3. On 400, read RequestExtension.Body and map each Field to your UI controls to show inline errors.

Published schemas are available at github.com/noah-labs/public-schemas. See Form Schemas for details.

tip

SchemaValidation errors on form fields usually mirror the schema's constraints and errorMessage values. Treat the schema as the source of truth for field-level messages, not a static error catalogue in these docs.

Multi-step responses are not errors

Some form-session flows return HTTP 200 with a NextStep object when additional acknowledgement or data is required (for example VoP or CoB). This is a continuation, not a failure. Call the same endpoint again with the returned FormSessionID and the fields requested in NextStep.Schema.

Examples

The examples below illustrate common error shapes across the API. Action, Detail, and field paths vary by endpoint.

Required field missing

{
"Type": "InvalidMessage",
"Action": "create customer",
"Detail": "invalid request",
"Instance": "9bbe5ce1-aa6a-4650-ae2b-084f4e1f229c",
"RequestExtension": {
"Body": [
{
"Field": "CustomerID",
"Reason": "SchemaValidation",
"Description": "required"
}
]
}
}

Form field validation

Invalid value for a schema-backed form field (exact Description varies by channel):

{
"Type": "InvalidMessage",
"Action": "validate form",
"Detail": "invalid request",
"Instance": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"RequestExtension": {
"Body": [
{
"Field": "Form.BankDetails.AccountNumber",
"Reason": "SchemaValidation",
"Description": "must match pattern \"^[0-9]{8,17}$\""
}
]
}
}

Field not supported

Returned when a value is well-formed but not supported for the selected channel — for example a bank account whose IBAN does not support SEPA:

{
"Type": "InvalidMessage",
"Action": "validate sepa support",
"Detail": "invalid request",
"Instance": "d0e1f2a3-b4c5-6789-0abc-def123456789",
"RequestExtension": {
"Body": [
{
"Field": "Form.BankDetails.AccountNumber",
"Reason": "NotSupported",
"Description": "IBAN does not support SEPA transfers"
}
]
}
}

Self reference

Returned when the request points back at the caller in a way that is not allowed — for example withdrawing to your own deposit address:

{
"Type": "InvalidMessage",
"Action": "workflow rest post bank to address",
"Detail": "invalid request",
"Instance": "e1f2a3b4-c5d6-7890-abcd-ef1234567890",
"RequestExtension": {
"Body": [
{
"Field": "DestinationAddress.Address",
"Reason": "SelfReference",
"Description": "can not use own address for withdrawal action"
}
]
}
}

Resource not found

{
"Type": "ResourceNotFound",
"Action": "fetch customer",
"Detail": "customer not found",
"Instance": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"RequestExtension": {
"Body": [
{
"Field": "CustomerID",
"Reason": "IntegrityValidation",
"Description": "not found"
}
]
}
}

Insufficient balance

{
"Type": "InsufficientBalance",
"Action": "withdraw balance check",
"Detail": "available balance less than requested amount",
"Instance": "c3d4e5f6-a7b8-9012-cdef-123456789012"
}

Unauthorized

Returned when the API key is missing, invalid, or expired, or when request signing fails:

{
"Type": "Unauthorized",
"Action": "api authorizer",
"Detail": "api key has expired",
"Instance": "f6a7b8c9-d0e1-2345-f012-456789012345"
}

Compliance denial

{
"Type": "Forbidden",
"Action": "create customer account",
"Detail": "Customer is in compliance review",
"Instance": "d4e5f6a7-b8c9-0123-def0-234567890123"
}

Channel policy denials may also include structured DenyExtension details:

{
"Type": "Forbidden",
"Action": "evaluate channel policy",
"Detail": "access denied",
"Instance": "e5f6a7b8-c9d0-1234-ef01-345678901234",
"DenyExtension": [
{
"Reason": "Compliance",
"Description": "Channel policy denied use of this channel for the counterparty",
"Principal": {
"ID": "cust_123",
"Type": "Customer",
"Subtype": "Individual"
},
"Resource": {
"ID": "00000000-0000-0000-0000-000000000123",
"Type": "Channel"
}
}
]
}

Feature or currency restrictions use the same DenyExtension shape with Reason: InsufficientPermissions:

{
"Type": "Forbidden",
"Action": "authorise client",
"Detail": "user does not have permission to use this resource",
"Instance": "a7b8c9d0-e1f2-3456-7890-abcdef012345",
"DenyExtension": [
{
"Reason": "InsufficientPermissions",
"Description": "feature Sell with currency USDC",
"Principal": {
"ID": "user_456",
"Type": "User",
"Subtype": "Business"
},
"Resource": {
"ID": "00000000-0000-0000-0000-000000000456",
"Type": "Channel"
}
}
]
}