Skip to main content

Merchant Onboarding Service

Overview

gateway-merchant-onboarding owns processor credential profiles, activation, and terminal onboarding workflows. It is internal-only in both peakgateway-staging and pinpoint-gateway: no public load-balancer route exists, and Cloud Run IAM authenticates every caller before the application.

The service is the sole writer of credential_profiles. Management exposes the operator-facing BFF and forwards authorized requests through InternalServiceClient.

Responsibilities

AreaResponsibility
Credential profilesCreate, validate, submit, approve, assign, rotate, and retire processor profiles
Secret protectionEncrypt/decrypt credential material with envelope encryption and Cloud KMS
Processor activationRun supported vendor onboarding, including TSYS TransIT MerchantActivation
Provisioning jobsPersist asynchronous activation/device workflows and their evidence
XTMSBind NexGO devices and push approved parameters through libs/xtms-client
AuditAppend credential and provisioning lifecycle evidence without exposing secrets
ReconciliationResume incomplete local persistence after a successful external activation

Service Boundary

Portal / operator
|
| Firebase + management permissions
v
management BFF
|
| Cloud Run IAM via InternalServiceClient
v
merchant-onboarding
| |
| HTTPS | KMS / Spanner
v v
TransIT / XTMS encrypted credential profiles

Processing reads API-safe credential-profile metadata needed for routing. It does not own onboarding state and must not write credential-profile rows. Management authorizes the human caller and tenant scope before forwarding any mutation.

API Boundary

Management exposes the support-relevant provisioning-job surface at /management/api/v1/provisioning/jobs. The generated internal reference is the operator contract:

The owner service also has internal credential-profile and device-provisioning routes. Those are service-to-service contracts, not public APIs. Their controller/DTO source and focused tests are authoritative; do not copy secret or internal payload schemas into documentation.

The provisioning controller uses merchant:activate on direct OAuth-aware calls. The management proxy instead enforces merchants:read or devices:write, scopes the target merchant/location, and forwards the request with Cloud Run IAM.

Credential Lifecycle

A credential profile moves through explicit lifecycle states. Exact state names and transitions are defined by the canonical enum/model and service tests, but the durable rules are stable:

  1. Create the profile for an organization and processor/platform.
  2. Store credential material encrypted; never return secret values in list or read responses.
  3. Validate the profile against the vendor without treating a transient failure as approval.
  4. Submit and approve only after required evidence exists.
  5. Assign the approved profile to concrete locations.
  6. Rotate by creating durable intent, completing external work, and persisting the result before reporting success.
  7. Retire or delete only when assignments and in-flight workflows permit it.

Unknown external outcomes become explicit reconciliation work. A successful vendor activation followed by a failed local write is recoverable through the durable PERSIST_ACTIVATION provisioning action; the issued credential is not silently discarded or blindly reissued.

Provisioning Jobs

Provisioning actions currently include:

  • ACTIVATE
  • ROTATE_KEY
  • PERSIST_ACTIVATION

Job states are QUEUED, IN_PROGRESS, COMPLETED, FAILED, and CANCELLED. Create and retry return 202 Accepted; status reads and cancellation return the persisted job representation.

A job records the target location/merchant, device serial, requested action, step evidence, timestamps, and any sanitized error. Secret values never belong in log messages, callback payloads, or operator-facing error text.

TransIT and XTMS

TransIT

MerchantActivation can issue a device ID and transaction key. Field ordering and wrapper shape are vendor-sensitive. Production DTOs, JSON ordering annotations, and certification fixtures are authoritative. Never patch required fields only in the certification runner.

XTMS

XTMS operations bind NexGO devices and push parameters. The service uses HMAC-signed requests through libs/xtms-client. A successful TransIT activation and a failed XTMS push are separate outcomes; preserve the activation and expose the device step as retryable work.

Manual credential-package retrieval is an audited operator fallback when XTMS cannot push parameters. Treat its output as sensitive and never paste it into chat, tickets, PRs, or logs.

Security Controls

  • Cloud Run IAM is the network/application entry gate.
  • KMS envelope encryption protects stored credential material.
  • Secret Manager supplies vendor application credentials.
  • Credential reads return masked/API-safe metadata unless an explicitly audited sensitive operation is authorized.
  • Tenant authorization is enforced at management before forwarding and checked again where the owner service has enough context.
  • Audit rows are append-only evidence; they never contain plaintext secrets.
  • Logs must not contain transaction keys, API keys, PAN, CVV, or raw vendor request/response bodies.

Data Ownership

Merchant-onboarding owns:

  • credential profiles and location assignments
  • provisioning jobs, steps, and audit evidence
  • processor activation state owned by onboarding
  • NexGO/XTMS binding state owned by onboarding

The SQLDelight files in libs/schema/src/main/sqldelight/ are authoritative. Use Schema Migrations for changes; do not derive DDL from copied examples.

Runtime

ComponentTechnology
LanguageKotlin 2.2 on Java 25
FrameworkSpring Boot 4.0.5
DatabaseCloud Spanner PostgreSQL dialect through SQLDelight/PGAdapter
Vendor clientsOkHttp through transit-client and xtms-client
EncryptionAES-256-GCM envelope encryption with Cloud KMS
ResilienceBounded Resilience4j policies
IngressInternal/load-balancer-only Cloud Run ingress plus IAM

Health endpoint: GET /health on the internal service URL. Verify it through an authorized internal caller or the aggregated status service; never add a public route for convenience.