Field Validation Rules

Every regex the Corporate API enforces, and where the published rules differ from them.

Before You Start

Read the following guides before proceeding:

GuideWhy
Api BasicsRequest configuration

Overview

The Corporate API validates most string fields against a regular expression before the request reaches
a handler. The patterns are published at runtime so a client can validate locally and avoid a round
trip.

GET /api/v1/validation/rules

Anonymous — no Authorization header.

Response:

{
  "rules": {
    "firstName": "^[a-zA-Z][a-zA-Z\\-']{1,50}$",
    "email": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
    "iban": "^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$"
  }
}
FieldDescription
rulesMap of rule name to regular expression

The published rules are not identical to the enforced ones. Four of them differ, and two are
published for fields the Corporate API does not validate at all. The differences are listed below.
Where they disagree, the enforced pattern is what decides whether a request succeeds.


Enforced Patterns

These are the patterns the API applies.

Identity

RulePatternApplies to
First name^[a-zA-Z][a-zA-Z\-' ]{0,49}$first_name on employee invite and update
Last name^[a-zA-Z][a-zA-Z\-' ]{0,49}$last_name on employee invite and update
Email^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$email
Phone^\+\d{1,15}$phonerequired on employee invite
Company name^[A-Za-z0-9&.,'’\-/() :+#]{2,100}$corporation_name, company_name
Registration number^[A-Z0-9\-]{6,15}$corporation_registration_number
Country code^[A-Z]{2}$corporation_registration_country, country
Recipient name^[\p{L}\p{N}\s.'\-]{1,100}$recipient_name on corridor payment details
Employee search term^[A-Za-z0-9@._%+' -]{2,100}$term on employee search

Employee names accept only unaccented Latin letters, apostrophes, hyphens and spaces. Recipient names
accept any Unicode letter or digit. José Müller is a valid recipient name and an invalid employee
name.

Addresses

RulePatternApplies to
Address line 1^[A-Za-z0-9&.,'’\-/() :+#]{2,100}$line1
Address line 2^[A-Za-z0-9&.,'’\-/() :+#]{2,100}$line2
City^[A-Za-z\s\-'.]{2,100}$city
State^[A-Za-z][A-Za-z\s\-']{1,99}$state
Postal code^[A-Za-z0-9\s\-]{3,12}$postal_code, zip_code
Country^[A-Z]{2}$country

City accepts no digits. An address in a city whose name contains a numeral fails validation.

Blockchain

RulePatternApplies to
Address^(0x[a-fA-F0-9]{40}|C[A-Za-z2-7]{55}|G[A-Za-z2-7]{55}|T[1-9A-HJ-NP-Za-km-z]{33})$corporation_address, token and wallet addresses
EVM address^0x[a-fA-F0-9]{40}$manager_address

manager_address accepts EVM addresses only. A Stellar or Tron address is rejected there while
being accepted as a corporation_address.

Cards

RulePatternApplies to
Name on card^[A-Za-z][A-Za-z .'-]{1,25}$name_on_card
Card name^[a-zA-Z0-9]+[a-zA-Z0-9\-':+#& ]{1,50}$card_name, card name
Expiry date^(0[1-9]|1[012])/\d{4}$expiry_date on card activation
Card number last 4^\d{4}$card_number_last4

Bank Details

RulePatternApplies to
IBAN^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$iban
UAE IBAN^AE\d{21}$iban on IPP details
BIC^[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?$bic
Account number^\d{8,18}$account_number on Faster Payments and ACH
Sort code^\d{6}$sort_code
Routing number^\d{9}$routing_number
CLABE^\d{18}$clabe
Currency^[A-Za-z0-9]{3,10}$currency
Catalog index^[a-zA-Z]$catalog_index on the recipient catalog filter

IBAN and card number checksums are not validated. Both IsValidIban and IsValidCardNumber
return true unconditionally — only the format is checked. A format-valid IBAN with a bad check
digit passes here and is rejected by the rail after the transfer has been accepted.

Corridor Details

RulePatternApplies to
PIX key type^(CPF|CNPJ|EMAIL|PHONE|EVP)$pix_key_type
PIX key — CPF^\d{11}$pix_key
PIX key — CNPJ^\d{14}$pix_key
PIX key — phone^\+55\d{10,11}$pix_key
PIX key — EVP^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$pix_key
FPS ID type^(FPS_ID|MOBILE|EMAIL)$fps_id_type
FPS-HK bank code^\d{3}$bank_code on FPS-HK
IMPS account number^\d{9,18}$account_number on IMPS
IFSC code^[A-Z]{4}0[A-Z0-9]{6}$ifsc_code
InstaPay bank code^([A-Z]{3,4}|[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?)$bank_code on InstaPay
BI-FAST bank code^(\d{3}|[A-Z]{4}ID[A-Z]{2})$bank_code on BI-FAST
NIP account number^\d{10}$account_number on NIP
NIP bank code^\d{3}$bank_code on NIP
PSE account type^(SAVINGS|CHECKING)$account_type on PSE
PSE bank code^\d{3}$bank_code on PSE
PSE document type^(CC|NIT|CE|PP)$document_type on PSE
PSE document number^[A-Z0-9]{5,20}$document_number on PSE

Where the Published Rules Differ

RulePublished by GET /api/v1/validation/rulesActually enforcedConsequence
firstName, lastName^[a-zA-Z][a-zA-Z\-']{1,50}$^[a-zA-Z][a-zA-Z\-' ]{0,49}$The published rule rejects names containing a space and single-character names, both of which the API accepts; it accepts 51-character names, which the API rejects
state^[A-Za-z\s\-']{2,100}$^[A-Za-z][A-Za-z\s\-']{1,99}$The published rule accepts a state starting with a space or hyphen; the API does not
department, job^[a-zA-Z0-9][a-zA-Z0-9\-':+#]{1,50}$Not enforceddepartment and job_title accept any string. Validating locally against the published rule rejects input the API would take
cardNumber^[0-9]{13,19}$Not usedThe Corporate API never accepts a full card number

Client-side validation against firstName as published will reject Mary Jane. Validate employee
names against ^[a-zA-Z][a-zA-Z\-' ]{0,49}$.


Error Shape

Validation failures come back in two shapes, depending on the endpoint.

Structured — the field is in error_details under the key field:

{
  "error_reason": "ErrorInvalidField",
  "error_description": "Invalid format for corporation address",
  "error_category": {
    "category": "CategoryValidationFailure",
    "http_status_code": 400
  },
  "error_details": [
    { "key": "field", "details": "corporation_address" },
    { "key": "issue", "details": "invalid_format" },
    { "key": "pattern", "details": "^(0x[a-fA-F0-9]{40}|C[A-Za-z2-7]{55}|G[A-Za-z2-7]{55}|T[1-9A-HJ-NP-Za-km-z]{33})$" }
  ]
}

Keyed — the field is the key, and error_description is generic:

{
  "error_reason": "ErrorGeneral",
  "error_description": "Request failed validation",
  "error_category": {
    "category": "CategoryValidationFailure",
    "http_status_code": 400
  },
  "error_details": [
    { "key": "first_name", "details": "First name is invalid" }
  ]
}

The employee, role, FX and v2 card endpoints use the keyed shape; corporations, bank, recipient and v1
card endpoints use the structured shape. Handle both: read error_details[].key, and where it is
field, read the field name from details.

The structured shape often includes the offending pattern, which is the most reliable source of the
enforced regex for a specific field.


Did this page help you?