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:
Type | HTTP | When it happens |
|---|---|---|
InvalidMessage | 400 | The request is malformed or a field fails validation. |
Unauthorized | 401 | The API key is missing, invalid, or expired, or request signing failed. |
Forbidden | 403 | A policy or compliance rule blocks the action. |
ResourceNotFound | 404 | A referenced resource does not exist. |
InsufficientBalance | 402 | The account balance is below the requested amount. |
Unexpected | 500 | An unexpected server-side error occurred. |
Error envelope
Every error response includes these fields:
| Field | Description |
|---|---|
Type | Error category: InvalidMessage, Forbidden, InsufficientBalance, ResourceNotFound, Unauthorized, or Unexpected |
Action | Internal action name for the operation that failed (for example create customer, withdraw) |
Detail | Human-readable summary of the failure |
Instance | Unique ID for this occurrence — use it to correlate a failure with server logs when contacting support |
RequestExtension | Field-level validation details (see below) |
DenyExtension | Policy or compliance denial details (see below) |
RequestExtension
Field-level problems are returned in RequestExtension.Body as an array of items:
| Field | Description |
|---|---|
Field | Dot path to the request field (for example CustomerID, Form.BankDetails.AccountNumber) |
Reason | Why the field failed — see the values below |
Description | What failed and, where possible, how to fix it |
Reason is one of:
| Reason | Meaning |
|---|---|
SchemaValidation | Value fails the JSON Schema or a business rule (wrong type, length, pattern, required). |
IntegrityValidation | Cross-field or state conflict (for example a referenced resource does not exist, or a form session expired). |
NotSupported | The value is well-formed but not supported for this operation (for example an IBAN that does not support SEPA transfers). |
SelfReference | The 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:
- Retrieve the relevant schema before submitting (for example GET
/channels/{ChannelID}/formfor payout forms). - Validate
Formclient-side against that JSON Schema. - On
400, readRequestExtension.Bodyand map eachFieldto your UI controls to show inline errors.
Published schemas are available at github.com/noah-labs/public-schemas. See Form Schemas for details.
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"
}
}
]
}