Merchant ID Architecture
Complete technical documentation for merchant ID generation, validation, and related systems.
Merchant ID Format
New Format (Current)
- Format:
MXXXXXXwhere X is a digit - Example:
M000101 - Range:
M000001toM999999 - Pattern:
/^M\d{6}$/
Legacy Format (Supported)
- Format:
FM-XXXX-XXXX-XXXXwhere X is a digit - Example:
FM-0294-8617-5039 - Pattern:
/^FM-\d{4}-\d{4}-\d{4}$/
Backward Compatibility
The system supports both formats:
- New merchants: Automatically receive
MXXXXXXformat - Existing merchants: Continue to use
FM-XXXX-XXXX-XXXXformat - Validation: Both formats are accepted throughout the system
Node Modules and Dependencies
Merchant API (cloud-run/merchant-api/)
Location: /cloud-run/merchant-api/
Node Modules:
express(^4.18.2) - Web framework for API endpointscors(^2.8.5) - CORS middleware@google-cloud/storage(^7.7.0) - Google Cloud Storage client
Package File: cloud-run/merchant-api/package.json
Key Files:
index.js- Main API server and merchant ID generationlib/jsonStore.js- Atomic write operations for GCSlib/validation.js- Merchant data validation
Merchant ID Generation:
- Function:
generateMerchantId(existingIds) - Location:
cloud-run/merchant-api/index.js(lines 54-74) - Algorithm: Generates random 6-digit number, zero-padded, prefixed with 'M'
Partner API (cloud-run/partner-api/)
Location: /cloud-run/partner-api/
Validation Module:
- File:
cloud-run/partner-api/lib/validation.js - Function:
validateMerchantId(merchant_id) - Supports: Both
MXXXXXXandFM-XXXX-XXXX-XXXXformats - Pattern:
/^M\d{6}$/or/^FM-\d{4}-\d{4}-\d{4}$/
Merchant Creation Flow
1. ID Generation
Location: cloud-run/merchant-api/index.js → generateMerchantId()
function generateMerchantId(existingIds) {
let attempts = 0;
let merchantId;
do {
// Generate MXXXXXX format (6 digits, zero-padded)
const numericPart = Math.floor(Math.random() * 999999) + 1;
merchantId = `M${String(numericPart).padStart(6, '0')}`;
attempts++;
} while (existingIds.includes(merchantId) && attempts < 100);
return merchantId;
}
Process:
- Generates random number 1-999999
- Zero-pads to 6 digits
- Prefixes with 'M'
- Checks uniqueness against existing IDs
- Retries up to 100 times if collision occurs
2. Storage
Merchants JSON:
- Location:
gs://finmatch-shared/merchants.json - Structure:
{ profiles: { [merchantId]: { ... } } } - Fields:
finmatchId,merchantName,domain,environment, etc.
Merchant Router JSON:
- Location:
gs://finmatch-shared/merchant-router.json - Structure:
{ [merchantId]: { environment: 'p|s|t', domain: '...' } } - Purpose: Domain-based routing for merchant identification
3. CORS Policy Update
Automatic Update: ✅ YES (new feature)
Location: cloud-run/merchant-api/index.js → updateCorsPolicy()
Process:
- Extracts domain from merchant profile
- Reads current CORS config from
gs://finmatch-shared/cors.json - Adds merchant domain (and www variant) to origins array
- Saves updated config to
gs://finmatch-shared/cors.json(backup) - Applies CORS policy to
gs://finmatch-finance-marketing-assetsbucket
CORS Bucket: finmatch-finance-marketing-assets (different from data bucket)
Domains Added:
- Base domain:
https://example.com - WWW variant:
https://www.example.com(if applicable)
Error Handling: CORS update failures do not prevent merchant creation
Files That Handle Merchant IDs
Backend (Node.js)
-
cloud-run/merchant-api/index.js- Generates merchant IDs (
generateMerchantId()) - Creates merchants (
POST /api/merchants) - Updates merchants (
PUT /api/merchants/:id) - Updates CORS policy (
updateCorsPolicy())
- Generates merchant IDs (
-
cloud-run/merchant-api/lib/validation.js- Validates merchant data
- Does NOT validate merchant ID format (handled elsewhere)
-
cloud-run/partner-api/lib/validation.js- Validates merchant ID format for API requests
- Supports both
MXXXXXXandFM-XXXX-XXXX-XXXX
-
cloud-run/partner-api/lib/cache.js- Caches merchant data
- Looks up merchants by ID (supports both formats)
Frontend (JavaScript)
-
admin/js/merchants.jssubmitAddMerchant()- Creates new merchanteditMerchant()- Loads merchant for editingsubmitEditMerchant()- Updates merchant (validates ID format)- ID format validation:
/^(M\d{6}|FM-[0-9]{4}-[0-9]{4}-[0-9]{4})$/
-
admin/merchants/index.html- Edit merchant form with ID input
- Pattern validation:
(M\d{6}|FM-[0-9]{4}-[0-9]{4}-[0-9]{4})
Documentation
admin-docs/docs/merchants/adding-merchants.md- User guideadmin-docs/docs/merchants/editing-merchants.md- Edit guideadmin-docs/docs/merchants/merchant-creation-architecture.md- ArchitectureMERCHANT_CREATION_REQUIREMENTS.md- Requirements doc
Validation Rules
Format Validation
Backend (Partner API):
const validFormats = [
/^M\d{6}$/, // M123456
/^FM-\d{4}-\d{4}-\d{4}$/ // FM-1234-5678-9012
];
Frontend (Admin Dashboard):
const finmatchIdPattern = /^(M\d{6}|FM-[0-9]{4}-[0-9]{4}-[0-9]{4})$/;
Uniqueness Validation
- On Creation: Automatically checked during ID generation
- On Edit: Manually validated by checking if ID exists
- Retry Logic: Up to 100 attempts to find unique ID
CORS Policy Architecture
Storage Locations
-
Backup Copy:
gs://finmatch-shared/cors.json- Human-readable JSON
- Version controlled
- Used as source of truth
-
Applied Policy:
gs://finmatch-finance-marketing-assetsbucket- Applied via
bucket.setCorsConfiguration() - Active CORS rules
- Applied via
Update Process
Automatic (on merchant creation):
- Merchant created with domain
updateCorsPolicy()called- Domain added to CORS origins
- Policy applied to bucket
Manual (if needed):
- Edit
gs://finmatch-shared/cors.json - Apply:
gsutil cors set cors.json gs://finmatch-finance-marketing-assets - Verify:
gsutil cors get gs://finmatch-finance-marketing-assets
CORS Configuration Structure
[
{
"maxAgeSeconds": 3600,
"method": ["GET", "HEAD"],
"origin": [
"https://example.com",
"https://www.example.com",
...
],
"responseHeader": ["Content-Type"]
}
]
Merchant Router Architecture
Purpose
Maps merchant domains to merchant IDs and environments for routing.
Structure
{
"M000101": {
"environment": "p",
"domain": "https://example.com"
},
"FM-0294-8617-5039": {
"environment": "s",
"domain": "https://staging.example.com"
}
}
Update Process
- On Creation: Automatically added with merchant creation
- On Edit: Updated if environment or domain changes
- Location:
gs://finmatch-shared/merchant-router.json
Environment Assignment
Automatic Derivation
Function: deriveEnvironment(domain)
Logic:
- Contains "staging" or "stage" →
's' - Contains "test" or "dev" →
't' - Otherwise →
'p'
Manual Override
- Form field:
environment(p/s/t) - Takes precedence over automatic derivation
- Saved to both
merchants.jsonandmerchant-router.json
Related Documentation
- Adding Merchants - User guide for creating merchants
- Editing Merchants - User guide for editing merchants
- Merchant Creation Architecture - Detailed creation flow
- Managing Merchants - General merchant management
Node Module Reference
Merchant API Dependencies
Location: cloud-run/merchant-api/node_modules/
Installed via: npm install (from package.json)
Key Modules:
express/- Web frameworkcors/- CORS middleware@google-cloud/storage/- GCS client library
Installation:
cd cloud-run/merchant-api
npm install
Partner API Dependencies
Location: cloud-run/partner-api/node_modules/
Note: Partner API has its own package.json and dependencies
Installation:
cd cloud-run/partner-api
npm install
Summary
- ✅ New Format:
MXXXXXX(6 digits) - ✅ Legacy Support:
FM-XXXX-XXXX-XXXXformat still supported - ✅ Automatic CORS: Domains added to CORS policy on creation
- ✅ Router Update: Merchant router updated with environment
- ✅ Validation: Both formats validated throughout system