Error Handling

How onboarding reports validation and request errors, the common KYB rejection messages, and how to resolve them.

Onboarding validates the whole entity graph atomically at create time. If any check fails, the request returns an error and no business is created — fix the reported problem and resend. This page lists the error shapes and the most common validation messages, grouped by the resource that produces them.

📘

Two kinds of failure

Submit-time problems (missing or malformed fields, broken KYB rules) come back synchronously on the request. In-flight problems (things only underwriting can judge) surface later on each service's errors, missingFields, and missingDocuments — see Onboarding statuses.


Error shapes

Field validation errors identify the offending field, a code, and a message:

{ "field": "legalName", "code": "REQUIRED", "message": "legalName is required" }

Multiple validation failures are collected under a VALIDATION_FAILED envelope:

{
  "errorCode": "VALIDATION_FAILED",
  "message": "Validation failed",
  "errors": [
    { "field": "addresses.0.type", "code": "INVALID_ENUM",
      "message": "addresses.0.type must be one of the following: registered, mailing, physical, headquarters, home, work" }
  ]
}

KYB/business-rule failures return a mandatory-level message tied to a fieldPath:

{
  "level": "mandatory",
  "message": "Exactly one owner or signatory must be marked as the Control Person.",
  "fieldPath": "owners"
}
🚧

PENDING-PUBLISH

The onboarding surface currently returns more than one error envelope shape (field-level { field, code, message }, a VALIDATION_FAILED wrapper, and a mandatory/fieldPath KYB shape), and some lower-level responses differ again. Confirm the canonical error contract with engineering and document a single shape here before publish; until then these examples mirror observed responses.


Business and identity

SituationMessage
legalName missinglegalName is required
legalName over 255 charslegalName must be shorter than or equal to 255 characters
businessDescription over 512 charsbusinessDescription must be shorter than or equal to 512 characters
Invalid emailemail must be an email
itin value not a valid 9-digit ITINtaxIds.0.value must be a valid 9-digit ITIN beginning with 9 (e.g. 9XX-XX-XXXX)
EIN required for entity typeTax ID type must be EIN for corporations, S-corporations, LLCs, LLPs and partnerships.

Owners, signatories, and control person

SituationMessage
No control personExactly one owner or signatory must be marked as the Control Person.
Non-profit/government with ownership > 0Beneficial-owner ownership must be 0 for government, non-profit and 501(c)(3) tax exempt.
Partnership total ownership < 50%Total beneficial-owner ownership must be at least 50% for partnerships.
Owner missing SSNEvery signatory (control person, owner and guarantor) requires a primary identification (SSN) for acquiring.
Owner missing government IDEvery signatory (control person, owner and guarantor) requires a secondary identification (government id) for acquiring.
Duplicate owner SSNDuplicate owner detected. The same SSN cannot be used for more than one owner.
ownershipPercentage with 3 decimalsownershipPercentage must be a non-negative amount with at most 2 decimal places

Locations and processing

SituationMessage
Missing MCCAn industry MCC code is required for acquiring.
Missing industry category/descriptionAn industry category or description is required for acquiring.
cardMix not totaling 100%MOTO, eCommerce and card-present percentages are required and must total 100% for acquiring.
High MOTO+eCom volume without required detailsWhen MOTO + eCommerce volume exceeds 20%, internet business type, marketing method and the monthly/onetime/yearly billing cadence are required for acquiring.
Invalid address typeaddresses.0.type must be one of the following: registered, mailing, physical, headquarters, home, work
Invalid postal codeaddresses.0.postalCode must be a valid postal code

Bank accounts

SituationMessage
Invalid routing numberbankAccounts.0.routingNumber must be a valid 9-digit routing number
Invalid accountTypeaccountType must be one of: checking, savings
Duplicate externalId across accountsDuplicate externalId '…' provided for multiple bank accounts in the same request

Request-level errors

HTTPSituationResponse
400Non-JSON body with JSON content-typeBody is not valid JSON but content-type is set to 'application/json'
400Empty bodyBody cannot be empty when content-type is set to 'application/json'
401Missing/invalid credentialUnauthorized
404Business not foundEntity not found: …
409Conflicting externalIdDuplicate externalId provided
422Unknown query parameterproperty … should not exist
422limit out of rangelimit must be an integer between 1 and 250
📘

Reading a record and writing it back

A GET returns masked, read-only fields (lastFour, accountNumberLast4) and computed fields the write endpoints don't accept. Don't PATCH a record back unmodified — send only the fields you're changing, or the write is rejected for containing read-only properties.


Known rough edges

Some current messages are accurate but not yet customer-friendly, and a few behaviors are inconsistent. These are tracked for improvement; call them out to integrators so they aren't surprised.

🚧

PENDING-PUBLISH

The following are documented as known issues pending engineering fixes; confirm status before publish and remove any that are resolved:

  • Internal vocabulary in messages — some errors say "for acquiring", name individualId/externalId (internal linking fields), or reference internal services (e.g. a document-service UUID). These should be reworded before they reach a merchant-facing surface.
  • Circular messages — e.g. email must be an email restates the field instead of showing a valid example.
  • Inconsistent auth/error shapesUnauthorized (no code), Tenant claim missing from token, and framework-default Token expired are three different shapes for auth failures; the orchestration and domain layers also use different codes (MALFORMED_REQUEST vs MALFORMED_BODY, INTERNAL_ERROR for a 403).
  • Silent gaps — going to two control persons is blocked, but going to zero is silently allowed; a personal (owner) address and an SSN can be changed with a plain PATCH and no re-verification, while a primary location can't be changed after creation at all.

See the internal error-scenarios catalog for the full list and per-message rationale.


See also



Did this page help you?
.readme-logo { display: none !important; }