---
title: SAIF.Business.EPay.USBank business rules
summary: Enumerated business rules enforced by SAIF.Business.EPay.USBank.
status: draft
owner: SAIF
last_reviewed: 2026-07-30
library: SAIF.Business.EPay.USBank
reference_type: package
---

# SAIF.Business.EPay.USBank business rules

This page captures the primary validation, persistence, redirect, and payload-shaping rules enforced by `SAIF.Business.EPay.USBank`.

## BR-001: Business online user ID is required

| Field | Value |
| --- | --- |
| Statement | A `clsUSBankUser` record must include a business-online user ID. |
| Trigger | User validation runs before insert or update. |
| Enforcement | `Rules.AddRule(AddressOf CommonBusinessRules.TextRequired, "BusinessOnlineUserId", ..., "BusinessOnlineUserId required.")`. |
| Outcome | The user object remains invalid until a business-online user ID is supplied. |
| Confidence | Verified |
| Tables | [US_BANK_USER](database-tables.md#us_bank_user) |
| SQL | [SQL-004](sql/SQL-004-insert-us-bank-user.md), [SQL-011](sql/SQL-011-update-us-bank-user.md) |
| Source | `Business\SAIF.Business.EPay.USBank\clsUSBankUser.vb` |

---

## BR-002: Policy number is required

| Field | Value |
| --- | --- |
| Statement | A `clsUSBankUser` record must include a non-zero policy number. |
| Trigger | User validation runs before insert or update. |
| Enforcement | `Rules.AddRule(AddressOf CommonBusinessRules.NonZeroDecimalRequired, "PolicyNumber", ..., "Policy Number required.")`. |
| Outcome | The user object remains invalid until a policy number is supplied. |
| Confidence | Verified |
| Tables | [US_BANK_USER](database-tables.md#us_bank_user) |
| SQL | [SQL-004](sql/SQL-004-insert-us-bank-user.md), [SQL-011](sql/SQL-011-update-us-bank-user.md) |
| Source | `Business\SAIF.Business.EPay.USBank\clsUSBankUser.vb` |

---

## BR-003: User inserts must affect exactly one row

| Field | Value |
| --- | --- |
| Statement | User inserts must affect exactly one row. |
| Trigger | A new `clsUSBankUser` record is saved through BOF `BeforeInsert`. |
| Enforcement | The save path checks rows affected and raises `InsertError` when the insert count is not exactly one. |
| Outcome | The insert fails instead of silently creating inconsistent local state. |
| Confidence | Verified |
| Tables | [US_BANK_USER](database-tables.md#us_bank_user) |
| SQL | [SQL-004](sql/SQL-004-insert-us-bank-user.md) |
| Source | `Business\SAIF.Business.EPay.USBank\clsUSBankUser.vb` |

---

## BR-004: User updates must affect exactly one row

| Field | Value |
| --- | --- |
| Statement | User updates must affect exactly one row. |
| Trigger | An existing `clsUSBankUser` record is saved through BOF `BeforeUpdate`. |
| Enforcement | The save path checks rows affected and raises `DBContentionError` when the update count is not exactly one. |
| Outcome | The update fails instead of silently losing concurrency or target-row mismatches. |
| Confidence | Verified |
| Tables | [US_BANK_USER](database-tables.md#us_bank_user) |
| SQL | [SQL-011](sql/SQL-011-update-us-bank-user.md) |
| Source | `Business\SAIF.Business.EPay.USBank\clsUSBankUser.vb` |

---

## BR-005: User deletes must affect exactly one row

| Field | Value |
| --- | --- |
| Statement | User deletes must affect exactly one row. |
| Trigger | A `clsUSBankUser` record is deleted through BOF `BeforeDelete`. |
| Enforcement | The delete path checks rows affected and raises `DBContentionError` when the delete count is not exactly one. |
| Outcome | The delete fails instead of silently ignoring a missing or duplicated target row. |
| Confidence | Verified |
| Tables | [US_BANK_USER](database-tables.md#us_bank_user) |
| SQL | [SQL-013](sql/SQL-013-delete-us-bank-user.md) |
| Source | `Business\SAIF.Business.EPay.USBank\clsUSBankUser.vb` |

---

## BR-006: Notice inserts must affect exactly one row

| Field | Value |
| --- | --- |
| Statement | Notice inserts must affect exactly one row. |
| Trigger | A new `clsUSBankNonpayNotice` record is saved through BOF `BeforeInsert`. |
| Enforcement | The save path checks rows affected and raises `InsertError` when the insert count is not exactly one. |
| Outcome | The notice insert fails instead of silently creating inconsistent callback state. |
| Confidence | Verified |
| Tables | [US_BANK_NONPAY_NOTICE](database-tables.md#us_bank_nonpay_notice) |
| SQL | [SQL-003](sql/SQL-003-insert-us-bank-nonpay-notice.md) |
| Source | `Business\SAIF.Business.EPay.USBank\clsUSBankNonpayNotice.vb` |

---

## BR-007: Notice updates must affect exactly one row

| Field | Value |
| --- | --- |
| Statement | Notice updates must affect exactly one row. |
| Trigger | An existing `clsUSBankNonpayNotice` record is saved through BOF `BeforeUpdate`. |
| Enforcement | The save path checks rows affected and raises `DBContentionError` when the update count is not exactly one. |
| Outcome | The notice update fails instead of silently accepting contention or a missing row. |
| Confidence | Verified |
| Tables | [US_BANK_NONPAY_NOTICE](database-tables.md#us_bank_nonpay_notice) |
| SQL | [SQL-010](sql/SQL-010-update-us-bank-nonpay-notice.md) |
| Source | `Business\SAIF.Business.EPay.USBank\clsUSBankNonpayNotice.vb` |

---

## BR-008: Notice deletes must affect exactly one row

| Field | Value |
| --- | --- |
| Statement | Notice deletes must affect exactly one row. |
| Trigger | A `clsUSBankNonpayNotice` record is deleted through BOF `BeforeDelete`. |
| Enforcement | The delete path checks rows affected and raises `DBContentionError` when the delete count is not exactly one. |
| Outcome | The notice delete fails instead of silently ignoring an unexpected row-count result. |
| Confidence | Verified |
| Tables | [US_BANK_NONPAY_NOTICE](database-tables.md#us_bank_nonpay_notice) |
| SQL | [SQL-012](sql/SQL-012-delete-us-bank-nonpay-notice.md) |
| Source | `Business\SAIF.Business.EPay.USBank\clsUSBankNonpayNotice.vb` |

---

## BR-009: User lookup is case-insensitive

| Field | Value |
| --- | --- |
| Statement | User lookup by policy and business-online user is case-insensitive. |
| Trigger | `USBankAPIs.RegisterUser` or other callers retrieve a user by policy number plus business-online user ID. |
| Enforcement | The retrieve SQL compares `UPPER(BUSINESS_ONLINE_USER)` to `UPPER(:BusinessOnlineUser)`. |
| Outcome | The library treats differently cased user IDs as the same logical identifier during lookup. |
| Confidence | Verified |
| Tables | [US_BANK_USER](database-tables.md#us_bank_user) |
| SQL | [SQL-008](sql/SQL-008-retrieve-us-bank-user-by-policy-and-business-online-user.md) |
| Source | `Business\SAIF.Business.EPay.USBank\clsUSBankUser.vb` |

---

## BR-010: Address payloads require complete postal data

| Field | Value |
| --- | --- |
| Statement | US Bank address payloads must contain street line 1, city, state, and ZIP after invalid characters are removed. |
| Trigger | `USBankAPIs` builds an address object for add or update user-profile calls. |
| Enforcement | `GetFilledUSBankAddress` strips invalid characters and throws if required fields collapse to empty values. |
| Outcome | The SOAP request is not sent with incomplete postal data. |
| Confidence | Verified |
| Source | `Business\SAIF.Business.EPay.USBank\USBankAPIs.vb` |

---

## BR-011: Outbound text must use US Bank-safe characters and lengths

| Field | Value |
| --- | --- |
| Statement | Outbound company names, personal names, and bank-account nicknames must use US Bank-approved characters and contract-specific length limits. |
| Trigger | `USBankAPIs` or `RemotePostFiller` constructs a bank-facing request or redirect payload. |
| Enforcement | `RemoveInvalidUSBank*Characters`, `Shorten`, and `ConfigurePolicyName` sanitize and truncate values before transmission. |
| Outcome | The integration sends normalized values instead of raw SAIF text. |
| Confidence | Verified |
| Source | `Business\SAIF.Business.EPay.USBank\USBankAPIs.vb; Business\SAIF.Business.EPay.USBank\RemotePostFiller.vb` |

---

## BR-012: Bank account payloads require category and type

| Field | Value |
| --- | --- |
| Statement | Bank-account payloads must specify both the business or consumer category and the checking or savings type. |
| Trigger | `USBankAPIs` builds add-account or recurring-authorization contract objects. |
| Enforcement | `GetFilledUSBankBankAccountInfo` and `GetFilledRecurringACHPayMethod` throw when either dimension is missing. |
| Outcome | Malformed bank-account metadata is rejected before the SOAP call is made. |
| Confidence | Verified |
| Source | `Business\SAIF.Business.EPay.USBank\USBankAPIs.vb` |

---

## BR-013: Duplicate bank accounts return a handled result

| Field | Value |
| --- | --- |
| Statement | Duplicate bank-account responses are returned as a handled business outcome. |
| Trigger | `AddBankAccount` receives response code `75` or `5025` from US Bank. |
| Enforcement | The method returns `AddBankAccountResults(False, String.Empty)` instead of throwing an exception. |
| Outcome | Callers can distinguish duplicate-account handling from transport or contract failures. |
| Confidence | Verified |
| Source | `Business\SAIF.Business.EPay.USBank\USBankAPIs.vb` |

---

## BR-014: Return URLs are rewritten to secure SAIF view links

| Field | Value |
| --- | --- |
| Statement | Return URLs must be rewritten to HTTPS SAIF view links. |
| Trigger | `RemotePostFiller` prepares a return URL for a session-transfer flow. |
| Enforcement | `GetReturnURL` rewrites `http://` to `https://`, strips an existing query string, appends `?__SAIFPID=<ViewID>`, and throws when the original value is not HTTP or HTTPS. |
| Outcome | US Bank redirects return to a normalized SAIF URL shape. |
| Confidence | Verified |
| Source | `Business\SAIF.Business.EPay.USBank\RemotePostFiller.vb` |

---

## BR-015: Admin user IDs are adjusted for legacy bank constraints

| Field | Value |
| --- | --- |
| Statement | Admin user IDs must be adjusted for legacy US Bank constraints. |
| Trigger | `RemotePostFiller` prepares an admin payment or search flow. |
| Enforcement | `AdjustAdminUserID` substitutes `saifuser01` for a specific TSV/UAT combination and pads IDs shorter than six characters with trailing `g`. |
| Outcome | Admin SSO and admin navigation payloads comply with the target user-ID expectations. |
| Confidence | Verified |
| Source | `Business\SAIF.Business.EPay.USBank\RemotePostFiller.vb; Business\SAIF.Business.EPay.USBank\USBankCodes.vb` |

---

## BR-016: Shared-secret answers use the policy ZIP code

| Field | Value |
| --- | --- |
| Statement | New and updated user-profile requests use the policy ZIP code as the shared-secret answer. |
| Trigger | `USBankAPIs` builds an AddUserProfile or UpdateUserProfile request. |
| Enforcement | The request mapping sets `sharedSecretAnswer = inPolicyInfo.Address.ZipCode` and `sharedSecretType = ZIPCODE`. |
| Outcome | US Bank profile provisioning always uses the policy ZIP code for the configured challenge-answer mechanism. |
| Confidence | Verified |
| Source | `Business\SAIF.Business.EPay.USBank\USBankAPIs.vb; Business\SAIF.Business.EPay.USBank\epayWebServiceService.vb` |

---

## BR-017: Local composite user IDs are limited to 16 characters

| Field | Value |
| --- | --- |
| Statement | The local `User` utility rejects composite user IDs longer than 16 characters. |
| Trigger | Callers invoke `User.GetUser(inPolicyNumber, inBusinessOnlineUserId)`. |
| Enforcement | The utility throws when the concatenated policy number plus business-online user ID exceeds 16 characters. |
| Outcome | Callers cannot produce an oversized local composite identifier through this helper. |
| Confidence | Verified |
| Source | `Business\SAIF.Business.EPay.USBank\User.vb` |

---

## BR-018: Admin make-payment requests always use the voluntary biller ID

| Field | Value |
| --- | --- |
| Statement | Admin make-payment remote-post requests always use the voluntary biller ID, regardless of whether the policy is actually voluntary or assigned-risk. |
| Trigger | `RemotePostFiller.FillAdminMakePaymentRemotePost` prepares an admin unregistered-payment redirect. |
| Enforcement | The method calls `m_USBankCodes.GetBillerId(True)` unconditionally instead of passing through `inPolicyInfo.IsVoluntaryPolicy`, with an inline comment noting the assigned-risk biller ID is not set up for credit card payments. |
| Outcome | Assigned-risk policies are redirected to US Bank's admin make-payment page using the voluntary biller ID instead of the assigned-risk biller ID. |
| Confidence | Verified |
| Source | `Business\SAIF.Business.EPay.USBank\RemotePostFiller.vb` |

---

## BR-019: Update user profile failures are retried once, then reported by email instead of failing the call

| Field | Value |
| --- | --- |
| Statement | A failed call to US Bank's `UpdateUserProfile` is retried exactly once after a short delay; if the retry also fails, the exception is not propagated to the caller, and an email failure notice is sent instead. |
| Trigger | `USBankAPIs.UpdateUserToUSBank` is invoked (from `RegisterUser`) and the first `UpdateUserProfile` SOAP call throws an exception. |
| Enforcement | The catch block sleeps 1500ms and retries the call once inside a nested `Try`/`Catch`; if the retry also throws, `SendMail` is called with `USBankCodes.ErrorEmailAddress` and the outer method returns without raising an exception. |
| Outcome | Callers of `RegisterUser` are not informed when both the initial and retried `UpdateUserProfile` calls fail; the failure is only surfaced through an outbound email, and the caller's flow continues as if no remote update error occurred. |
| Confidence | Verified |
| Source | `Business\SAIF.Business.EPay.USBank\USBankAPIs.vb` |

---

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Dependencies](dependencies.md)
- [Operations and processes](operations-processes.md)
- [Database tables](database-tables.md)
- [Security and authorization](security-authorization.md)
- [SQL catalog](sql/index.md)
- [API reference](api/index.md)
- [Configuration](configuration.md)
## Sources
- `Business\SAIF.Business.EPay.USBank\clsUSBankUser.vb`
- `Business\SAIF.Business.EPay.USBank\clsUSBankNonpayNotice.vb`
- `Business\SAIF.Business.EPay.USBank\USBankAPIs.vb`
- `Business\SAIF.Business.EPay.USBank\RemotePostFiller.vb`
- `Business\SAIF.Business.EPay.USBank\USBankCodes.vb`
- `Business\SAIF.Business.EPay.USBank\User.vb`
- `Business\SAIF.Business.EPay.USBank\epayWebServiceService.vb`

