Banking is built around two primary entities: account holders (the people or businesses who own money) and bank accounts (the actual deposit accounts holding it). One holder can own many accounts; one account belongs to exactly one holder.
Account holders
A holder is the legal entity on the account — an individual person or a business. Holder fields drive KYC/KYB, AML screening, and account eligibility.
Holder types
individual— natural person; KYC required.business— legal entity; KYB required, plus beneficial-owner data for ownership over 25%.
Holder fields
For individuals: firstName, lastName, dateOfBirth, ssn (stored masked, last 4 only), address, phone, email.
For businesses: businessName, businessType, ein (masked), business address, registered agent contact, plus a beneficialOwners array.
Common to both: kycStatus / kybStatus, amlStatus, riskLevel.
Banking stores the last 4 of SSN/EIN only; full numbers are never persisted. Tokenisation and masking happens at the holder service layer.
Creating a holder
/banking/accounts/holdersJWTcurl -X POST https://appengine.appmint.io/banking/accounts/holders \
-H "orgid: $ORG" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{
"holderType": "individual",
"firstName": "Alice",
"lastName": "Doe",
"email": "[email protected]",
"dateOfBirth": "1990-04-12",
"ssn": "123-45-6789",
"phone": "+15551234567",
"address": {
"line1": "100 Main St",
"city": "Brooklyn",
"state": "NY",
"postalCode": "11201",
"country": "US"
}
}'
A business holder uses holderType: "business" and replaces the personal fields with businessName, ein, and a registered business address.
Reading and updating
/banking/accounts/holdersJWTFilter with holderType, status, plus page and pageSize.
/banking/accounts/holders/{id}JWT/banking/accounts/holders/{id}JWTUpdates accept partial bodies. Identity fields (DOB, SSN, EIN) usually require a re-run of KYC/KYB; the controller updates the record but downstream compliance state may move back to review_required.
Bank accounts
A bank account is the actual deposit account at the sponsor bank. Account number format is 10 digits (the platform prefix 8800 plus 6 random digits, per the sponsor's allocation).
Account types
| Type | Cards | Wire | Check writing |
|---|---|---|---|
checking | Yes | No | Yes |
savings | No | No | No |
business_checking | Yes | Yes | Yes |
business_savings | No | Yes | No |
ACH is supported on all four. Card issuing and check writing are limited to checking-style accounts.
Default limits
Out of the box, every new account ships with:
| Limit | Amount |
|---|---|
| Daily withdrawal | $2,500 |
| Daily transfer | $10,000 |
Sponsor banks may impose lower per-org limits. Check with the partner before raising defaults.
Creating an account
/banking/accountsJWT| Field | Type | Description |
|---|---|---|
| holderId* | string | ID of the account holder. Must already exist; KYC/KYB does not need to be complete to create the account, but the account stays |
| holderType* | 'individual' | 'business' | Must match the holder's type. |
| accountType* | 'checking' | 'savings' | 'business_checking' | 'business_savings' | The account product. |
| currency | string | ISO 4217 code; defaults to |
{
"holderId": "holder_abc",
"holderType": "individual",
"accountType": "checking",
"currency": "USD"
}
Listing accounts
/banking/accountsJWTFilter with status, accountType, holderId. When holderId is set, the response is filtered to that holder; otherwise paginated across the org.
Single-account reads
/banking/accounts/{id}JWTFull account record with masked account number, status, limits, and metadata.
/banking/accounts/{id}/balanceJWTReturns three balances:
| Balance | Meaning |
|---|---|
current | Posted balance — credits and debits that have settled. |
available | Current minus outgoing fund holds. What can be spent right now. |
pending | Inbound transfers that haven't yet settled. Not spendable. |
For most flows, available is the number you check before authorising a card or initiating a transfer.
/banking/accounts/{id}/statementsJWTPaginated statements. Filter with ?year=2026&month=4. Each statement carries opening balance, closing balance, and the line-by-line ledger for the period.
Lifecycle
pending → active → frozen ↔ active
↓
closed (terminal)
Activate
/banking/accounts/{id}/activateJWTMoves a pending account to active. KYC must be approved on the holder; the controller checks this before flipping state.
Freeze and unfreeze
/banking/accounts/{id}/freezeJWTBody: { reason: string }. A frozen account rejects all outbound transfers and card authorisations. Inbound credits are held in pending until unfreeze. Use for fraud holds, compliance reviews, or customer-requested locks.
/banking/accounts/{id}/unfreezeJWTRestores active state. Pending inbound transfers settle on the next batch.
Close
/banking/accounts/{id}/closeJWTBody: { reason: string }. Terminal state. Account must have zero balance — sweep funds out via internal transfer first. Closed accounts retain history for statutory periods (typically 7 years for KYC records; check with sponsor).
Beneficial owners (KYB)
Business accounts require beneficial-owner data for any individual owning 25% or more of the entity, plus one "control person".
/banking/compliance/kyb/{holderId}/ownersJWTBody: an owner object with name, DOB, SSN, address, ownership percentage, and role. Add owners until the disclosed ownership reaches 100% (or your sponsor's threshold). KYB cannot complete until owners are submitted.
See KYC/KYB/AML compliance for the full compliance flow.
Quick onboarding
The /banking/onboard endpoint chains holder creation, KYC bootstrap, ledger account creation, and a first account in one call. Useful when your front end collects everything up front and you want a single round-trip.
/banking/onboardJWTFor an even tighter flow that also issues a card:
/banking/relationshipJWTBody includes holder, accountType, issueCard?, and cardType?. KYC still runs out of band.